package com.dd.cloud.user.service.pres.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.config.obs.PathProperties;
import com.dd.cloud.common.constants.*;
import com.dd.cloud.common.enums.PharEnum;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.*;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.DTO.CallbackPresStatusReq;
import com.dd.cloud.user.DTO.CancelPresReq;
import com.dd.cloud.user.DTO.CommonParamReq;
import com.dd.cloud.user.DTO.ca.VisaWaitFileUploadReq;
import com.dd.cloud.user.DTO.hjt.SynchHjtPresReq;
import com.dd.cloud.user.DTO.hosData.*;
import com.dd.cloud.user.config.OrderPrefix;
import com.dd.cloud.user.config.SuperviseProperties;
import com.dd.cloud.user.entity.aicms.AicmsDiagnosticResult;
import com.dd.cloud.user.entity.doctor.DoctorDetail;
import com.dd.cloud.user.entity.doctor.DoctorUser;
import com.dd.cloud.user.entity.doctor.PatientMedCard;
import com.dd.cloud.user.entity.log.LogError;
import com.dd.cloud.user.entity.order.OrderFlow;
import com.dd.cloud.user.entity.order.OrderPay;
import com.dd.cloud.user.entity.phar.*;
import com.dd.cloud.user.entity.pres.*;
import com.dd.cloud.user.entity.product.ProductUseRecord;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.mapper.pres.PresHjtPharRoamMapper;
import com.dd.cloud.user.mapper.pres.PresPrescriptionMapper;
import com.dd.cloud.user.mq.MQConfig;
import com.dd.cloud.user.mq.RabbitSend;
import com.dd.cloud.user.req.order.CreateFlowReq;
import com.dd.cloud.user.req.order.CreateOrderReq;
import com.dd.cloud.user.req.order.PayUnOrderReq;
import com.dd.cloud.user.req.phar.PresCreateCreamFormulaReq;
import com.dd.cloud.user.req.pres.*;
import com.dd.cloud.user.res.aicms.AicmsDiagnosticResultDetail;
import com.dd.cloud.user.res.order.PayOrderResponse;
import com.dd.cloud.user.res.pres.*;
import com.dd.cloud.user.service.aicms.IAicmsDiagnosticResultService;
import com.dd.cloud.user.service.ca.ICaDoctorService;
import com.dd.cloud.user.service.consule.IConsultSubscribeService;
import com.dd.cloud.user.service.doctor.*;
import com.dd.cloud.user.service.file.IFileInfoService;
import com.dd.cloud.user.service.log.ILogErrorService;
import com.dd.cloud.user.service.news.INewsInfoService;
import com.dd.cloud.user.service.order.IOrderFlowService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.phar.*;
import com.dd.cloud.user.service.phar.pharservice.PharServiceBeanInterface;
import com.dd.cloud.user.service.phar.pharservice.PharServiceInterface;
import com.dd.cloud.user.service.plat.TemplateMessAgeService;
import com.dd.cloud.user.service.pres.*;
import com.dd.cloud.user.service.product.IProductUseRecordService;
import com.dd.cloud.user.util.PdfToImgUtil;
import com.dd.cloud.user.util.WordToPdf;
import com.dd.cloud.user.vo.DelayMqVo;
import com.dd.cloud.user.vo.ExpressRes;
import com.dd.cloud.user.vo.HjtResponseVo;
import com.zk.pay.constants.CS;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 处方表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-04-27
 */
@Service
@Slf4j
public class PresPrescriptionServiceImpl extends ServiceImpl<PresPrescriptionMapper, PresPrescription> implements IPresPrescriptionService {
    @Autowired
    private IAicmsDiagnosticResultService aicmsDiagnosticResultService;
    @Autowired
    private IDoctorUserService doctorUserService;
    @Autowired
    private IPresPretrialDrugsService presPretrialDrugsService;
    @Autowired
    private IPatientMedCardService patientMedCardService;
    @Autowired
    private IDoctorPatientBindService doctorPatientBindService;
    @Autowired
    private IDrugsModelService drugsModelService;
    @Autowired
    private IPresHjtDetailService presHjtDetailService;
    @Autowired
    private IPresKmDetailService presKmDetailService;
    @Autowired
    private IPresDslDetailService presDslDetailService;
    @Autowired
    private IPresOtherDetailService presOtherDetailService;
    @Autowired
    private IPresYfDetailService presYfDetailService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    /**
     * 处方药品key
     */
    public static final String PRES_TCMS_KEY = "pres-tcms-";
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IPharmacyService pharmacyService;
    @Autowired
    private ILogErrorService logErrorService;
    @Autowired
    private PharServiceBeanInterface pharServiceBeanInterface;
    @Autowired
    private IPharmacyChooseService pharmacyChooseService;
    @Autowired
    private IPresHandleRecordService presHandleRecordService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private IFileInfoService fileInfoService;
    @Autowired
    private IDrugsPoisonService drugsPoisonService;
    @Autowired
    private SuperviseProperties superviseProperties;
    @Autowired
    private PathProperties pathProperties;
    @Autowired
    private IPharmacyDockingService pharmacyDockingService;
    @Autowired
    private RabbitSend rabbitSend;
    @Autowired
    private PresHjtPharRoamMapper presHjtPharRoamMapper;
    @Autowired
    private IDoctorOrderIncomeDetailService doctorOrderIncomeDetailService;
    @Autowired
    private IBindReviewPresDoctorService bindReviewPresDoctorService;
    @Autowired
    private IPresReviewRecordService presReviewRecordService;
    @Autowired
    private INewsInfoService newsInfoService;
    @Autowired
    private IPharFryingOneRuleService pharFryingOneRuleService;
    @Autowired
    private IPharFryingTwoRuleService pharFryingTwoRuleService;
    @Autowired
    private IPresSaveMaterialService presSaveMaterialService;
    @Autowired
    private IConsultSubscribeService consultSubscribeService;
    @Autowired
    private TemplateMessAgeService templateMessAgeService;

    //蜜丸
    private final BigDecimal mirRate = new BigDecimal(1);

    //水丸
    private final BigDecimal waterRate = new BigDecimal(0.4);

    //其实重量
    private final BigDecimal weight = new BigDecimal(1000);

    @Autowired
    private IPresHrDetailService presHrDetailService;


    @Autowired
    private OrderPrefix orderPrefix;

    @Autowired
    private IOrderFlowService orderFlowService;

    @Autowired
    private ICaDoctorService caDoctorService;

    @Autowired
    private IProductUseRecordService productUseRecordService;

    @Autowired
    private IDoctorEquityService doctorEquityService;


    /**
     * 添加处方
     *
     * @param map
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayOrderResponse<?> savePres(HttpServletRequest request, Map<String, Object> map) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        Integer type = doctorUserService.getDoctorUserType(loginInfo.getId());
        if (type != UserConstants.DoctorUserType.PRO && type != UserConstants.DoctorUserType.PUB) {
            throw new ZekeException(400, "无权限访问接口");
        }
        Integer[] presPowers = bindReviewPresDoctorService.queryReviewDoctorId(loginInfo.getId());
        if (presPowers[0] == 0) {
            if (presPowers[1] == -1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "未有处方权以及未签约审核医生");
            } else if (presPowers[1] == -2) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "签约审核医生申请中,无法开方");
            }
        }
        log.info("map:{}", map);
        if (!map.containsKey("pharId")) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "药房id不能为空");
        }
        Pharmacy pharmacy = pharmacyService.getById(map.get("pharId").toString());
        if (pharmacy == null) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "没有找到默认药房");
        }
        //验证参数
        PresCreateReq req = PresCreateReq.castandValid(map, pharmacy.getFlag());
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES && req.getDiagnosticId() == null) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "ai开方诊断id不能为空");
        }
        if (req.getConsultId() != null && req.getConsultId() != 0) {
            QueryWrapper<PresPrescription> qw = new QueryWrapper<>();
            qw.lambda().eq(PresPrescription::getConsultId, req.getConsultId());
            qw.lambda().ne(PresPrescription::getStatus, PresConstants.PresStatus.DEL);
            int count = count(qw);
            if (count > 0) {
//                throw new ZekeException(400, "一次问诊最多一条处方订单");
            }
        }
        String tencode;
        AicmsDiagnosticResult result = null;
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES) {
            result = aicmsDiagnosticResultService.getById(req.getDiagnosticId());
            if (result == null) {
                throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "诊断结果不存在");
            }
            if (req.getIsFree() == 1) {
                tencode = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, "CF");
                PresPrescription presPrescription = this.getById(result.getTencode());
                if (presPrescription != null) {
                    AicmsDiagnosticResult newResult = new AicmsDiagnosticResult();
                    BeanUtils.copyProperties(req, newResult);
                    newResult.setCreateTime(LocalDateTime.now());
                    newResult.setTencode(tencode);
                    aicmsDiagnosticResultService.save(newResult);
                    req.setDiagnosticId(newResult.getId());
                }
            } else {
                tencode = result.getTencode();
            }
        } else {
            tencode = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, "CF");
        }
        req.setIsUpdate(0);
        if (req.getTencode() != null && req.getIsUpdate() == 1) {
            tencode = req.getTencode();
        } else {
            req.setTencode(tencode);
        }
        PatientMedCard medCard;
        if (!StringUtils.isBlank(req.getMedId())) {
            QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
            qw.lambda().eq(PatientMedCard::getMedId, req.getMedId()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
            medCard = patientMedCardService.getOne(qw);
            if (medCard == null) {
                throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "就诊卡不存在");
            }
            doctorPatientBindService.doctorPatientBind(loginInfo.getId(), medCard.getMedId(), 1);
        } else {
            if (req.getPatientReq() == null) {
                throw new ZekeException(400, "患者信息不能为空");
            }
            medCard = patientMedCardService.addPresGeneratePatientInfo(req.getPatientReq(), req.getAddrReq(), loginInfo);
            req.setMedId(medCard.getMedId());
        }
        log.info("出生日期更改前" + medCard);
        if (medCard.getBirthDate() == null) {
            medCard.setBirthDate(LocalDate.of(1998, 10, 1));
        }
        log.info(medCard.toString());
        if (req.getPatientReq() != null) {
            BeanUtils.copyProperties(req.getPatientReq(), medCard);
        }
        medCard.setPregnant(req.getPregnant());
        if (medCard.getBirthDate() == null) {
            medCard.setBirthDate(LocalDate.of(1998, 10, 1));
        }
        log.info(medCard.toString());
        if (pharmacy.getFlag() == PharConstants.Flag.KM) {
            verifyKmDrugDose(pharmacy, req, medCard);
        }
        //根据类型进行参数校验
        checkTypeWay(req);
        QueryWrapper<PresPrescription> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPrescription::getTencode, tencode).eq(PresPrescription::getStatus, PresConstants.PresStatus.NOMER);
        PresPrescription presPrescription = getOne(qs);
        if (presPrescription != null) {
            //已存在,修改处方
            if (req.getIsUpdate() == 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方已存在");
            }
        }
        presPrescription = new PresPrescription();
        presPrescription.setEthnicity(medCard.getNationality());
        //保存处方药品
        QueryWrapper<PresPretrialDrugs> q2 = new QueryWrapper<>();
        q2.lambda().eq(PresPretrialDrugs::getTencode, tencode).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> drugList = presPretrialDrugsService.list(q2);
        if (drugList != null && !drugList.isEmpty()) {
            if (req.getIsUpdate() == 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方药品已存在");
            } else {
                UpdateWrapper<PresPretrialDrugs> uw = new UpdateWrapper<>();
                uw.lambda().eq(PresPretrialDrugs::getTencode, tencode).set(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.DEL);
                presPretrialDrugsService.update(uw);
            }
        }
        log.info("前端计算的药品价格{}" + req.getMoney());
        log.info("前端计算的药品折扣价格{}" + req.getDiscountMoney());
        List<PresCreateDrugsReq> tcms = req.getTcms();
        List<PresPretrialDrugs> drugsList = new LinkedList<>();
        //总价, 单位分
        BigDecimal free = new BigDecimal(0);
        BigDecimal orFree = new BigDecimal(0);
        BigDecimal drugOriginalFree = new BigDecimal(BigInteger.ZERO);
        BigDecimal signalDrugWeight = new BigDecimal(BigInteger.ZERO);
        BigDecimal totalDrugWeight = new BigDecimal(BigInteger.ZERO);
        for (PresCreateDrugsReq tcm : tcms) {
            LambdaQueryWrapper<DrugsModel> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DrugsModel::getDrugnum, tcm.getDrugnum()).eq(DrugsModel::getHerbName, tcm.getHerbName()).eq(DrugsModel::getPharFlag, pharmacy.getFlag()).eq(DrugsModel::getPharId, req.getPharId()).eq(DrugsModel::getStatus, 1);
            if (StringUtils.isNotBlank(tcm.getKlType())) {
                wrapper.eq(DrugsModel::getKlType, tcm.getKlType());
            }
            DrugsModel drugsModel = drugsModelService.getOne(wrapper);
            if (drugsModel == null) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "药品不存在,药品编号为:" + tcm.getDrugnum());
            }
            PresPretrialDrugs drug = new PresPretrialDrugs();
            BeanUtils.copyProperties(tcm, drug);
            drug.setOriginalPrice(drugsModel.getOriginalPrice().doubleValue());
            drug.setTencode(tencode);
            drug.setStatus(PresConstants.PresDrugsStatus.NOMER);
            drugsList.add(drug);
            tcm.setDiscountPrice(tcm.getRetailprice());
            //药品重量
            signalDrugWeight = signalDrugWeight.add(BigDecimal.valueOf(tcm.getDrugallnum()));
            free = free.add(BigDecimalUtils.multiply(BigDecimal.valueOf(drug.getRetailprice()), BigDecimal.valueOf(drug.getDrugallnum())));
            log.info("药品名称:{},药品价格:{},药品重量:{},计算后的药品价格:{}", drug.getHerbName(), drug.getRetailprice(), drug.getDrugallnum(), free);
            orFree = orFree.add(BigDecimalUtils.multiply(BigDecimal.valueOf(drug.getDiscountPrice()), BigDecimal.valueOf(drug.getDrugallnum())));
            drugOriginalFree = drugOriginalFree.add(BigDecimalUtils.multiply(BigDecimal.valueOf(drug.getOriginalPrice()), BigDecimal.valueOf(drug.getDrugallnum())));
        }
        log.info("药品处理前费用:{}", free);
        free = free.setScale(0, RoundingMode.HALF_UP);
        orFree = orFree.setScale(0, RoundingMode.HALF_UP);
        drugOriginalFree = drugOriginalFree.setScale(0, RoundingMode.HALF_UP);
        log.info("药品重量：{}", signalDrugWeight);
        log.info("加工类型：{}", req.getPresType());
        log.info("药品费用:{}", free);
        log.info("药品折扣费用:{}", orFree);
        log.info("药品原价费用:{}", drugOriginalFree);
        if (req.getPresType() == PresConstants.DrugsProcessingType.ONE || req.getPresType() == PresConstants.DrugsProcessingType.TWO || req.getPresType() == PresConstants.DrugsProcessingType.THREE) {
            totalDrugWeight = BigDecimalUtils.multiply(signalDrugWeight, BigDecimal.valueOf(req.getAllDose()));
            free = BigDecimalUtils.multiply(free, BigDecimal.valueOf(req.getAllDose()));
            orFree = BigDecimalUtils.multiply(orFree, BigDecimal.valueOf(req.getAllDose()));
            drugOriginalFree = BigDecimalUtils.multiply(drugOriginalFree, BigDecimal.valueOf(req.getAllDose()));
            log.info("后端计算药品总重量:{}", totalDrugWeight);
            log.info("后端计算总剂药品费用:{}", free.doubleValue());
            log.info("后端计算总剂药品折扣费用:{}", orFree);
            log.info("后端计算总剂药品原价:{}", drugOriginalFree);
        }
        //验证水蜜丸蜂蜜价格
        if (req.getPresType() == PresConstants.DrugsProcessingType.SIX || req.getPresType() == PresConstants.DrugsProcessingType.SEVEN) {
            List<PresCreateCreamFormulaReq> list = covertData(map);
            if (CollectionUtil.isEmpty(list)) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "辅料蜂蜜不能为空");
            }
            if (list.size() != 1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "辅料蜂蜜数量重复传递");
            }
            PresCreateCreamFormulaReq presCreateCreamFormulaReq = list.get(0);
            BigDecimal prsPrice = new BigDecimal(presCreateCreamFormulaReq.getPrice());
            BigDecimal originalPrice = new BigDecimal(presCreateCreamFormulaReq.getOriginalPrice());
            req.setCreamFormulaReqs(list);
            log.info("加工类型:{}", req.getPresType());
            log.info("前端计算的的蜜蜂价格:{}", req.getOtherFee());
            BigDecimal otherFee = new BigDecimal(req.getOtherFee());
            log.info("药品剂数========>" + req.getAllDose());
            log.info("水蜜丸/蜜丸药瓶总量========>" + signalDrugWeight);
            BigDecimal waterWeight = signalDrugWeight;
            if (req.getPresType() == PresConstants.DrugsProcessingType.SIX) {
                waterWeight = BigDecimalUtils.multiply(waterWeight, waterRate, 3);
                waterWeight = BigDecimalUtils.divide(waterWeight, new BigDecimal(1000), 3);
                waterWeight = waterWeight.setScale(2, RoundingMode.HALF_UP);
                log.info("水蜜丸转换成公斤=====>" + waterWeight);
                req.setWeightKg(waterWeight);
            } else if (req.getPresType() == PresConstants.DrugsProcessingType.SEVEN) {
                waterWeight = BigDecimalUtils.multiply(waterWeight, mirRate, 3);
                waterWeight = BigDecimalUtils.divide(waterWeight, new BigDecimal(1000), 3);
                waterWeight = waterWeight.setScale(2, RoundingMode.HALF_UP);
                log.info("蜜丸转换成公斤=====>" + waterWeight);
                req.setWeightKg(waterWeight);
            }
            log.info("后端计算的蜂蜜重量:{}", waterWeight);
            log.info("前端计算的蜂蜜重量:{}", presCreateCreamFormulaReq.getWeight());
            if (waterWeight.compareTo(presCreateCreamFormulaReq.getWeight()) != 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "蜂蜜重量有误");
            }
            log.info("蜂蜜价格:{}", prsPrice);
            log.info("蜂蜜原价:{}", originalPrice);
            BigDecimal waterFee = BigDecimalUtils.multiply(waterWeight, prsPrice);
            waterFee = waterFee.setScale(0, RoundingMode.HALF_UP);
            BigDecimal subtractResult = waterFee.subtract(otherFee);
            log.info("后端计算的蜂蜜价格:{}", waterFee);
            log.info("前后端计算的蜂蜜价格相差:{}", subtractResult);
            BigDecimal originalMoney = BigDecimalUtils.multiply(waterWeight, originalPrice);
            originalMoney = originalMoney.setScale(0, RoundingMode.HALF_UP);
            log.info("后端计算的蜂蜜原价格:{}", originalMoney);
            //控制在2分以内
            if (subtractResult.compareTo(BigDecimal.valueOf(-2)) == -1 || subtractResult.compareTo(BigDecimal.valueOf(2)) == 1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "蜂蜜价格有误");
            }
            orFree = orFree.add(waterFee);
            free = free.add(waterFee);
            drugOriginalFree = drugOriginalFree.add(originalMoney);
            log.info("加上蜂蜜后端计算的药品折扣总价格:{}" + orFree);
            log.info("加上蜂蜜后端计算的药品总价格:{}" + free);
            log.info("加上蜂蜜后端计算的药品原总价格:{}" + drugOriginalFree);
            presPrescription.setOtherOriginalFee(originalMoney.intValue());
        }
        //辅料价格验证
        if (req.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            List<PresCreateCreamFormulaReq> list = covertData(map);
            req.setCreamFormulaReqs(list);
            if (CollectionUtil.isEmpty(list)) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "膏方辅助材料不能为空");
            }
            BigDecimal totalMoney = new BigDecimal(BigInteger.ZERO);
            BigDecimal totalOriginalMoney = new BigDecimal(BigInteger.ZERO);
            for (PresCreateCreamFormulaReq formulaReq : list) {
                //膏方总价格
                totalMoney = totalMoney.add(BigDecimalUtils.multiply(BigDecimal.valueOf(formulaReq.getPrice()), formulaReq.getWeight()));
                totalOriginalMoney = totalOriginalMoney.add(BigDecimalUtils.multiply(BigDecimal.valueOf(formulaReq.getOriginalPrice()), formulaReq.getWeight()));
            }
            totalMoney = totalMoney.setScale(0, RoundingMode.HALF_UP);
            BigDecimal subtractResult = totalMoney.subtract(BigDecimal.valueOf(req.getOtherFee()));
            log.info("膏方辅助材料价格后端====>" + totalMoney);
            log.info("膏方辅助材料价格前端====>" + req.getOtherFee());
            log.info("后端与前端膏方材料价格相差====>" + subtractResult);
            totalOriginalMoney = totalOriginalMoney.setScale(0, RoundingMode.HALF_UP);
//            BigDecimal subtractOriginalResult = totalOriginalMoney.subtract(BigDecimal.valueOf(req.getOtherOriginalFee()));
            //控制在相差-5分到5分则通过校验
            if (subtractResult.compareTo(BigDecimal.valueOf(-2)) <= 0 || subtractResult.compareTo(BigDecimal.valueOf(2)) >= 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "膏方辅助材料价格有误");
            }
            log.info("后端计算的膏方原价格:{}", totalOriginalMoney);
            presPrescription.setOtherOriginalFee(totalOriginalMoney.intValue());
            orFree = orFree.add(totalMoney);
            free = free.add(totalMoney);
            drugOriginalFree = drugOriginalFree.add(totalOriginalMoney);
            log.info("加上辅料材料后端计算的药品折扣总价格:{}" + orFree);
            log.info("加上辅料材料后端计算的药品总价格:{}" + free);
            log.info("加上辅料材料后端计算的原药品总价格:{}" + drugOriginalFree);
        }
        if (type == UserConstants.DoctorUserType.PUB) {
            if (req.getDiscountMoney() == null) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "公益账号下折扣药品金额不能为空");
            }
            req.setDiscountMoney(req.getMoney());
            if (orFree.doubleValue() != req.getDiscountMoney()) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "折扣药品金额有误");
            }
        } else {
            if (free.doubleValue() != req.getMoney()) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "药品金额有误");
            }
        }
        //加工费剂型参数校验
        verifyProcessingType(req);
        //批量插入
        boolean j = presPretrialDrugsService.saveBatch(drugsList);
        if (!j) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方药品保存失败");
        }
        log.info("快递方式:{}" + req.getDeliveryIsDisplay());
        BeanUtils.copyProperties(req, presPrescription);
        String diagnosticName;
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES) {
            //获取中医诊断名称
            diagnosticName = getDiagnosticName(result);
            req.setDiagnosticName(diagnosticName);
        } else {
            diagnosticName = req.getDisease();
            req.setDiagnosticName(diagnosticName);
        }
        if (result != null) {
            BeanUtils.copyProperties(result, presPrescription);
            presPrescription.setTencode(tencode);
        }
        log.info("保存处方:{},药品原价", drugOriginalFree);
        presPrescription.setDiagnosticName(diagnosticName);
        presPrescription.setPresOriginalMoney(drugOriginalFree.intValue());
        presPrescription.setType(req.getPresType());
        presPrescription.setName(medCard.getName());
        presPrescription.setDiagnosticId(req.getDiagnosticId());
        presPrescription.setAge(String.valueOf(medCard.getBirthDate().until(LocalDate.now()).getYears()));
        presPrescription.setSex(medCard.getSex());
        presPrescription.setDepartmentName(req.getDepName());
        presPrescription.setDiseaseName(req.getDisease());
        presPrescription.setMaritalStatus(medCard.getMaritalStatus());
        presPrescription.setPhoneNum(medCard.getMobileNumber());
        presPrescription.setCreateDate(LocalDateTime.now());
        presPrescription.setStatus(PresConstants.PresStatus.NOMER);
        presPrescription.setDoctorId(loginInfo.getId());
        presPrescription.setPharmId(pharmacy.getId());
        presPrescription.setOfflineDisease(req.getOfflineDisease());
        presPrescription.setIsFree(req.getIsFree());
        presPrescription.setIsFrying(req.getIsFrying());
        if (req.getPresType() == PresConstants.DrugsProcessingType.FOUR
                || req.getPresType() == PresConstants.DrugsProcessingType.FIVE
                || req.getPresType() == PresConstants.DrugsProcessingType.SIX
                || req.getPresType() == PresConstants.DrugsProcessingType.SEVEN) {
            req.setPackagenum(200);
        }
        if (presPrescription.getSign() != null) {
            presPrescription.setSign(presPrescription.getSign().replace(pathProperties.getImageServer(), ""));
        }
        if (presPrescription.getConfirmSign() != null) {
            presPrescription.setConfirmSign(presPrescription.getConfirmSign().replace(pathProperties.getImageServer(), ""));
        }
        if (presPowers[0] == 1) {
            presPrescription.setReviewDoctorId(presPowers[1]);
            presPrescription.setReviewSign(presPrescription.getSign());
            presPrescription.setReviewConfirmSign(presPrescription.getConfirmSign());
        } else {
            presPrescription.setReviewDoctorId(presPowers[1]);
            presPrescription.setStatus(PresConstants.PresStatus.DOC_NO_REVIEW);
        }
        boolean i = saveOrUpdate(presPrescription);
        if (!i) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方保存失败");
        }
        //如果为膏方类型则保存辅料蜜丸则保存蜂蜜
        if (req.getPresType() == PresConstants.DrugsProcessingType.EIGHT || req.getPresType() == PresConstants.DrugsProcessingType.SEVEN || req.getPresType() == PresConstants.DrugsProcessingType.SIX) {
            saveMaterial(req, tencode);
        }
        boolean isLock = false;
        try {
            if (pharmacy.getFlag() == PharConstants.Flag.STORE) {
                //平台第三方自用药房, 需要管理库存, 锁定库存
                checkPresDrugsStock(presPrescription);
                isLock = true;
            }
            /*
             * 添加处方详细信息
             */
            PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(pharmacy.getId());
            if (pharServiceInterface == null) {
                throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "获取药房处理service失败");
            }
            pharServiceInterface.addPresDetail(req, medCard);
            Integer doctorId = presPrescription.getDoctorId();
            LambdaQueryWrapper<DoctorDetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DoctorDetail::getDoctorId, doctorId);
            DoctorDetail doctorDetail = doctorDetailService.getOne(queryWrapper);
            //创建产品使用记录
            ProductUseRecord record = new ProductUseRecord();
            record.setTencode(tencode).setCreateDate(LocalDateTime.now()).setDoctorId(loginInfo.getId()).setDiseaseName(presPrescription.getDiseaseName()).setDoctorName(doctorDetail.getName()).setDoctorAccount(doctorDetail.getMobileNumber()).setPatientName(presPrescription.getName()).setType(1);
            productUseRecordService.createProductUseRecord(record);
            if (pharmacy.getIsPay() == PharConstants.Status.NO) {
                return new PayOrderResponse();
            }
            if (req.getIsFree() == 1) {
                PayOrderResponse<?> payOrderResponse = new PayOrderResponse();
                payOrderResponse.setTencode(tencode);
                return payOrderResponse;
            }
            if (req.getIsPay() == 0) {
                return new PayOrderResponse();
            }
            pharmacyChooseService.saveOrUpdatePharChooseByMechanId(req.getPharId(), null, presPrescription.getDoctorId(), req.getPresType());
            if (req.getIsUpdate() == 1) {
                orderPayService.delOrder(tencode);
            }
            /*
             * 创建支付订单
             */
            CreateOrderReq orderReq = new CreateOrderReq();
            orderReq.setOpenid(req.getOpenid());
            orderReq.setPayType(req.getPayType());
            if (req.getPresType() == PresConstants.DrugsProcessingType.SIX || req.getPresType() == PresConstants.DrugsProcessingType.SEVEN || req.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
                //蜂蜜价格已包含在药品金额里面
                req.setOtherFee(0);
            }
            int price = Math.round((req.getDiscountMoney() == null ? req.getMoney() : req.getDiscountMoney()) + req.getConsultationFee() + req.getExpensesFee() + req.getFryingFee() + req.getServiceFee() + req.getOtherFee());//加上蜂蜜和辅料
            orderReq.setPrice(price);
            orderReq.setServerNo(tencode);
            if (req.getParamsType() == 1) {
                orderReq.setPartyId(0);
                orderReq.setPartyType(1);
                orderReq.setApply("applet");
            } else {
                orderReq.setPartyId(pharmacy.getId());
                orderReq.setPartyType(2);
                orderReq.setApply(req.getApply());
            }

            orderReq.setProduct(CS.NOTICE_CHANNEL.PRE);
            PayOrderResponse<?> res = orderPayService.createOrder(request, orderReq, req.getSourceType());
            try {
                sendPresPdfTaskMQ(presPrescription.getTencode(), req.getTcms());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (presPrescription.getStatus() == PresConstants.PresStatus.DOC_NO_REVIEW) {
                newsInfoService.sendReviewDoctorPresHandleNotice(presPrescription.getReviewDoctorId(), presPrescription.getTencode());
                DelayMqVo<String> delayMqVo = new DelayMqVo<>();
                delayMqVo.setT(presPrescription.getTencode());
                delayMqVo.setType(DelayMqVo.DelayMqVoType.PRES_REVIEW_TIMEOUT);
                //毫秒级 10min消息
                long ms = 1000 * 60 * 10;
                rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, ms);
            }
            if (req.getSourceType() != null) {
                if ((req.getSourceType() == 3 || req.getSourceType() == 4) && req.getConsultId() != null) {
                    sendMessage(res.getOrderPay().getOrderNo());
                }
            }
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("docName", loginInfo.getName());
                jsonObject.put("patName", medCard.getName());
                jsonObject.put("medId", medCard.getMedId());
                jsonObject.put("createDate", DateUtils.DTF_YMD_HM.format(presPrescription.getCreateDate()));
                jsonObject.put("amount", res.getOrderPay().getActualPay());
                jsonObject.put("tencode", presPrescription.getTencode());
                String params = TemplateConstants.TemplateType.PRES_ORDER_UN_PAY_PAT_GZH + "-" + jsonObject.toJSONString();
                rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
//                templateMessAgeService.sendPresOrderUnPayTemplateMessage(loginInfo.getName(), medCard.getName(), medCard.getMedId(), presPrescription.getCreateDate(), res.getOrderPay().getActualPay());
            } catch (Exception e) {
                e.printStackTrace();
            }
            productUseRecordService.genOrderUpdateProductUseRecord(tencode, res.getOrderPay().getOrderNo(), res.getOrderPay().getActualPay());
            return res;
        } catch (Exception e) {
            if (isLock) {
                //解锁库存
                releasePresDrugsStock(presPrescription, LoginInfo.UserType.ADMIN);
            }
            throw e;
        }

    }

    private void sendMessage(String orderNo) {
        DelayMqVo<String> delayMqVo1 = new DelayMqVo<>();
        delayMqVo1.setT(orderNo + "-2小时");
        delayMqVo1.setType(DelayMqVo.DelayMqVoType.PRE_ORDER_REMIND);
        //毫秒级 22小时
        long ms1 = 1000 * 60 * 60 * 22;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo1, ms1);
        DelayMqVo<String> delayMqVo2 = new DelayMqVo<>();
        delayMqVo2.setT(orderNo + "-1小时");
        delayMqVo2.setType(DelayMqVo.DelayMqVoType.PRE_ORDER_REMIND);
        //毫秒级 23小时
        long ms2 = 1000 * 60 * 60 * 23;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo1, ms2);
        DelayMqVo<String> delayMqVo3 = new DelayMqVo<>();
        delayMqVo3.setT(orderNo + "-30分钟");
        delayMqVo3.setType(DelayMqVo.DelayMqVoType.PRE_ORDER_REMIND);
        //毫秒级 23.5小时
        long ms3 = 1000 * 60 * 60 * 23 + 1000 * 60 * 30;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo3, ms3);
        DelayMqVo<String> delayMqVo4 = new DelayMqVo<>();
        delayMqVo4.setT(orderNo + "-15分钟");
        delayMqVo4.setType(DelayMqVo.DelayMqVoType.PRE_ORDER_REMIND);
        //毫秒级 23.5小时
        long ms4 = 1000 * 60 * 60 * 23 + 1000 * 60 * 45;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo4, ms4);
    }

    private String getDiagnosticName(AicmsDiagnosticResult result) {
        if (result != null) {
            try {
                String res = result.getResult();
                if (StringUtils.isNotBlank(res)) {
                    String[] strings = res.split("【辨证诊断】");
                    if (strings.length == 1) {
                        strings = res.split("【辨证】");
                    }
                    if (strings.length == 2) {
                        String name = StringUtils.substringBefore(strings[1], "<br>").trim();
                        log.info(name);
                        return name;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private List<PresCreateCreamFormulaReq> covertData(Map<String, Object> map) {
        List<PresCreateCreamFormulaReq> list = null;
        try {
            list = ObjectUtils.convertListMap2ListBean((List<Map<String, Object>>) map.get("creamFormulaReqs"), PresCreateCreamFormulaReq.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }


    private void saveMaterial(PresCreateReq req, String tencode) {
        //TODO 这里校验防止处方辅料重复多条出现
        LambdaQueryWrapper<PresSaveMaterial> presSaveMaterialLambdaQueryWrapper = new LambdaQueryWrapper<>();
        presSaveMaterialLambdaQueryWrapper.eq(PresSaveMaterial::getTencode, tencode);
        List<PresSaveMaterial> result = presSaveMaterialService.getBaseMapper().selectList(presSaveMaterialLambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(result)) {
            throw new ZekeException("该处方已存在辅料,请勿重复添加");
        }
        List<PresCreateCreamFormulaReq> res = req.getCreamFormulaReqs();
        if (CollectionUtil.isEmpty(res)) {
            throw new ZekeException("辅料不能为空");
        }
        List<PresSaveMaterial> list = new ArrayList<>();
        if (req.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            for (PresCreateCreamFormulaReq pre : res) {
                PresSaveMaterial presSaveMaterial = new PresSaveMaterial();
                presSaveMaterial.setName(pre.getName()).setPrice(pre.getPrice()).setUnit(pre.getUnit()).setWeight(pre.getWeight()).setOriginalPrice(pre.getOriginalPrice()).setTencode(tencode).setType(PresConstants.DrugsProcessingType.EIGHT).setCreateDate(LocalDateTime.now());
                list.add(presSaveMaterial);
            }
            log.info("膏方添加的材料:{}" + JSON.toJSONString(list));
        } else if (req.getPresType() == PresConstants.DrugsProcessingType.SEVEN || req.getPresType() == PresConstants.DrugsProcessingType.SIX) {
            PresCreateCreamFormulaReq formulaReq = res.get(0);
            PresSaveMaterial presSaveMaterial = new PresSaveMaterial();
            presSaveMaterial.setTencode(tencode).setName(formulaReq.getName()).setPrice(formulaReq.getPrice()).setOriginalPrice(formulaReq.getOriginalPrice()).setTencode(tencode).setUnit(formulaReq.getUnit()).setWeight(formulaReq.getWeight()).setCreateDate(LocalDateTime.now());
            if (req.getPresType() == PresConstants.DrugsProcessingType.SIX) {
                presSaveMaterial.setType(PresConstants.DrugsProcessingType.SIX);
            } else if (req.getPresType() == PresConstants.DrugsProcessingType.SEVEN) {
                presSaveMaterial.setType(PresConstants.DrugsProcessingType.SEVEN);
            }
            list.add(presSaveMaterial);
            log.info("蜂蜜添加的材料:{}" + JSON.toJSONString(list));
        }
        if (CollectionUtil.isNotEmpty(list)) {
            presSaveMaterialService.saveBatch(list);
        }
    }

    private void checkTypeWay(PresCreateReq req) {
        //对于类型相应字段的校验
        if (req.getPresType() == PresConstants.DrugsProcessingType.ONE || req.getPresType() == PresConstants.DrugsProcessingType.TWO) {
            if (req.getAllDose() > 100) {
                throw new ZekeException("总剂量数不能超过100");
            }
            if (req.getDayDose() > 9) {
                throw new ZekeException("每日次数不能超过9袋");
            }
            if (req.getDoseNum() == null) {
                throw new ZekeException("每剂次数不能为空");
            }
            if (req.getPackagenum() == null) {
                throw new ZekeException("包装量不能为空");
            }
            if (req.getDrugDose() == null) {
                throw new ZekeException("每剂用量不能为空");
            }
        }
        if (req.getPresType() == PresConstants.DrugsProcessingType.NINE || req.getPresType() == PresConstants.DrugsProcessingType.TEN || req.getPresType() == PresConstants.DrugsProcessingType.ELEVEN || req.getPresType() == PresConstants.DrugsProcessingType.TWELVE || req.getPresType() == PresConstants.DrugsProcessingType.THIRTEEN || req.getPresType() == PresConstants.DrugsProcessingType.FOURTEEN || req.getPresType() == PresConstants.DrugsProcessingType.FIFTEEN || req.getPresType() == PresConstants.DrugsProcessingType.SIXTEEN) {
            if (req.getDoseNum() == null) {
                throw new ZekeException("每次包数不能为空");
            }
            if (req.getPackagenum() == null) {
                throw new ZekeException("每包克数不能为空");
            }
            if (StringUtils.isBlank(req.getNum())) {
                throw new ZekeException("目数不能为空");
            }
        }
        if (req.getPresType() == PresConstants.DrugsProcessingType.FOUR || req.getPresType() == PresConstants.DrugsProcessingType.FIVE || req.getPresType() == PresConstants.DrugsProcessingType.SIX || req.getPresType() == PresConstants.DrugsProcessingType.SEVEN) {
            if (req.getPackagenum() == null) {
                throw new ZekeException("每次克数不能为空");
            }
        }
    }

    public void verifyProcessingType(PresCreateReq req) {
        Integer type = req.getPresType();
        if (req.getPresType() == PresConstants.DrugsProcessingType.ONE || req.getPresType() == PresConstants.DrugsProcessingType.TWO || req.getPresType() == PresConstants.DrugsProcessingType.THREE) {
            checkOneRule(req);
        } else {
            checkTwoRule(req);
        }
    }

    public void checkTwoRule(PresCreateReq req) {
        Integer type = req.getPresType();
        LambdaQueryWrapper<PharFryingTwoRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PharFryingTwoRule::getType, type).eq(PharFryingTwoRule::getPharId, req.getPharId()).eq(PharFryingTwoRule::getIsChecked, 1);
        PharFryingTwoRule pharFryingTwoRule = pharFryingTwoRuleService.getOne(wrapper);
        if (pharFryingTwoRule == null) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工类型不存在");
        }
        BigDecimal totalWeight = new BigDecimal(BigInteger.ZERO);
        for (PresCreateDrugsReq tcm : req.getTcms()) {
            //药品重量
            totalWeight = totalWeight.add(BigDecimal.valueOf(tcm.getDrugallnum()));
        }
        log.info("药品总重量========>" + totalWeight);
        Integer minWeightIsChecked = pharFryingTwoRule.getMinWeightIsChecked();
        if (minWeightIsChecked == 1) {
            Integer minWeight = pharFryingTwoRule.getMinWeight();
            log.info("起重量=======>" + minWeight);
            if (totalWeight.compareTo(BigDecimal.valueOf(minWeight)) == -1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "最小重量不满足");
            }
        }
        Integer isChecked = pharFryingTwoRule.getFreeIsChecked();
        if (isChecked == 1) {
            Integer money = req.getMoney();
            log.info("药品费为:" + money);
            Integer drugFee = pharFryingTwoRule.getDrugFee();
            log.info("满药品费金额:{}", drugFee);
            if (money >= drugFee) {
                log.info("满足药品金额--前端加工费:{}", req.getFryingFee());
                log.info("满足药品减免--后端加工费:{}", 0);
                if (req.getFryingFee() != 0) {
                    throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                } else {
                    log.info("=======价格校验成功=====");
                }
            } else {
                checkOtherType(pharFryingTwoRule, totalWeight, req.getFryingFee());
                log.info("=======价格校验成功=====");
            }
        } else {
            checkOtherType(pharFryingTwoRule, totalWeight, req.getFryingFee());
            log.info("=======价格校验成功=====");
        }
    }

    private void checkOtherType(PharFryingTwoRule pharFryingTwoRule, BigDecimal totalWeight, Integer frying) {
        log.info("药品费没有满足减免金额---->寻找其他满足条件");
        Integer realWeightIsChecked = pharFryingTwoRule.getRealWeightIsChecked();
        if (realWeightIsChecked == 1) {
            log.info("=========按实际重量计算============");
            BigDecimal processingFee = BigDecimal.valueOf(pharFryingTwoRule.getProcessingFee());
            BigDecimal processG = BigDecimalUtils.multiply(pharFryingTwoRule.getProcessKg(), 1000);
            log.info("加工费换算成kg{}" + pharFryingTwoRule.getProcessKg());
            log.info("加工费换算成g{}" + processG);
            BigDecimal fryingFee = BigDecimal.valueOf(frying);
            BigDecimal subWeight = totalWeight.subtract(processG);
            if (subWeight.compareTo(new BigDecimal(0)) < 1) {//剩余的重量不足以满足重量
                log.info("前端计算的加工费:{}" + fryingFee);
                log.info("后端计算的加工费:{}" + processingFee);
                log.info("剩余的重量不足以满足重量{}" + subWeight);
                if (fryingFee.compareTo(processingFee) == 0) {
                    log.info("===============计价成功===================");
                } else {
                    throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                }
            } else if (subWeight.compareTo(new BigDecimal(0)) == 1) {//满足条件
                log.info("剩余的重量满足重量{}" + subWeight);
                log.info("一公斤价钱=====" + processingFee);
                BigDecimal resKg = BigDecimalUtils.divide(totalWeight, processG, 3);
                resKg = resKg.setScale(2, RoundingMode.HALF_UP);
                log.info("药品重量换算成公斤===============>" + resKg);
                BigDecimal totalMoney = BigDecimalUtils.multiply(resKg, processingFee);
                BigDecimal subtractResult = totalMoney.subtract(fryingFee);
                log.info("后端计算的总价格为===============>" + totalMoney);
                log.info("前端计算的总价格为===============>" + fryingFee);
                log.info("totalMoney-fryingFee相差========>" + subtractResult);
                //可能存在一些小的偏差,在-2分到2分之间都算验证通过
                if (subtractResult.compareTo(BigDecimal.valueOf(-2)) <= 0 || subtractResult.compareTo(BigDecimal.valueOf(2)) >= 0) {
                    throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                }
            }
            log.info("=======价格校验成功=====");
        } else {
            Integer reWeightIsChecked = pharFryingTwoRule.getReWeightIsChecked();
            if (reWeightIsChecked == 1) {
                log.info("=========按续重处理============");
                BigDecimal processingFee = BigDecimal.valueOf(pharFryingTwoRule.getProcessingFee());
                BigDecimal processG = BigDecimalUtils.multiply(pharFryingTwoRule.getProcessKg(), 1000);
                log.info("加工费换算成kg{}" + pharFryingTwoRule.getProcessKg());
                log.info("加工费换算成g{}" + processG);
                BigDecimal fryingFee = BigDecimal.valueOf(frying);
                BigDecimal subWeight = totalWeight.subtract(processG);
                if (subWeight.compareTo(new BigDecimal(0)) < 1) {//剩余的重量不足以满足续重
                    log.info("前端计算的加工费:{}" + fryingFee);
                    log.info("后端计算的加工费:{}" + processingFee);
                    if (fryingFee.compareTo(processingFee) == 0) {
                        log.info("===============计价成功===================");
                    } else {
                        throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                    }
                } else if (subWeight.compareTo(new BigDecimal(0)) == 1) {//满足条件
                    log.info("一公斤价钱=====" + processingFee);
                    BigDecimal reWeight = BigDecimal.valueOf(pharFryingTwoRule.getReWeight());
                    BigDecimal weightFee = BigDecimal.valueOf(pharFryingTwoRule.getWeightFee());
                    BigDecimal rwRate = new BigDecimal(BigInteger.ZERO);
                    if (subWeight.doubleValue() % reWeight.doubleValue() == 0) {
                        log.info("续重能够除尽=====不加1:{}" + subWeight.doubleValue() % reWeight.doubleValue());
                        rwRate = BigDecimalUtils.divide(subWeight, reWeight).setScale(0, BigDecimal.ROUND_DOWN);
                    } else {
                        log.info("续重除不尽=====加1" + subWeight.doubleValue() % reWeight.doubleValue());
                        rwRate = BigDecimalUtils.divide(subWeight, reWeight).setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal(1));
                    }

                    log.info("续重重量====》" + rwRate);
                    BigDecimal totalMoney = rwRate.multiply(weightFee).add(processingFee);
                    BigDecimal subtractResult = totalMoney.subtract(fryingFee);
                    log.info("后端计算的总价格为===============>" + totalMoney);
                    log.info("前端计算的总价格为===============>" + fryingFee);
                    log.info("totalMoney-fryingFee相差========>" + subtractResult);
                    log.info("药品总结---续重相差:" + subtractResult);
                    if (subtractResult.compareTo(BigDecimal.valueOf(-2)) <= 0 || subtractResult.compareTo(BigDecimal.valueOf(2)) >= 0) {
                        throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                    }
                    log.info("=========验证价格成功======");
                }
            } else {
                BigDecimal processingFee = BigDecimal.valueOf(pharFryingTwoRule.getProcessingFee());
                BigDecimal processG = BigDecimalUtils.multiply(pharFryingTwoRule.getProcessKg(), 1000);
                BigDecimal fryingFee = BigDecimal.valueOf(frying);
                log.info("走到这里表示后台设置错误,确认后台单选是否勾选");
//                commonWay(totalWeight, processingFee, fryingFee, processG);
                log.info("=========验证价格失败======");
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
            }
        }
    }


    private void checkOneRule(PresCreateReq req) {
        Integer type = req.getPresType();
        LambdaQueryWrapper<PharFryingOneRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PharFryingOneRule::getType, type).eq(PharFryingOneRule::getPharId, req.getPharId()).eq(PharFryingOneRule::getIsChecked, 1);
        PharFryingOneRule pharFryingOneRule = pharFryingOneRuleService.getOne(wrapper);
        if (pharFryingOneRule == null) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工类型不存在");
        }
        BigDecimal signalDrugWeight = new BigDecimal(BigInteger.ZERO);
        for (PresCreateDrugsReq tcm : req.getTcms()) {
            //药品重量
            signalDrugWeight = signalDrugWeight.add(BigDecimal.valueOf(tcm.getDrugallnum()));
        }
        BigDecimal totalWeight = BigDecimalUtils.multiply(signalDrugWeight, BigDecimal.valueOf(req.getAllDose()));
        log.info("药品总重量:{}", totalWeight);
        Integer processingFee = pharFryingOneRule.getProcessingFee();
        log.info("加工费单价:{}", processingFee);
        Integer money = req.getMoney();
        log.info("前端传递的药品总费用为:{}", money);
        Integer freeIsChecked = pharFryingOneRule.getFreeIsChecked();
        if (freeIsChecked == 1) {
            Integer drugFee = pharFryingOneRule.getDrugFee();
            log.info("满药品费金额:{}", drugFee);
            if (money >= drugFee) {
                log.info("满足药品金额--前端加工费:{}", req.getFryingFee());
                log.info("满足药品减免--后端加工费:{}", 0);
                if (req.getFryingFee() != 0) {
                    throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                } else {
                    log.info("=======价格校验成功=====");
                }
            } else {
                commonWay04(pharFryingOneRule, req.getFryingFee(), req.getAllDose());
            }
        } else {
            commonWay04(pharFryingOneRule, req.getFryingFee(), req.getAllDose());
        }
    }

    private void commonWay04(PharFryingOneRule pharFryingOneRule, Integer fryingCharge, Integer allDose) {
        Integer processingFee = pharFryingOneRule.getProcessingFee();
        log.info("药品费没有满足减免金额---->寻找其他满足条件");
        Integer fullDoseIsChecked = pharFryingOneRule.getFullDoseIsChecked();
        if (fullDoseIsChecked == 1) {
            Integer fullDose = pharFryingOneRule.getFullDose();
            if (allDose >= fullDose) {
                log.info("满足总剂量减免--前端加工费:{}", fryingCharge);
                log.info("满足药品金额---后端加工费:{}", pharFryingOneRule.getFullDoseCharge());
                if (!fryingCharge.equals(pharFryingOneRule.getFullDoseCharge())) {
                    throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                } else {
                    log.info("========满足总剂量价格校验成功========");
                }
            } else {
                commonWay05(allDose, processingFee, fryingCharge);
            }
        } else {
            Integer doseIsChecked = pharFryingOneRule.getDoseIsChecked();
            if (doseIsChecked == 1) {
                Integer dose = pharFryingOneRule.getDose();
                if (allDose >= dose) {
                    BigDecimal totalMoney = BigDecimalUtils.multiply(BigDecimal.valueOf(allDose), BigDecimal.valueOf(pharFryingOneRule.getDoseCharge()));
                    totalMoney = totalMoney.setScale(0, RoundingMode.HALF_UP);
                    log.info("进入单剂满多少后折扣");
                    log.info("总共剂量数:{}" + allDose);
                    log.info("前端传递的加工费:{}" + fryingCharge);
                    log.info("后端传递的加工费:{}" + totalMoney);
                    if (totalMoney.compareTo(new BigDecimal(fryingCharge)) == 0) {
                        log.info("===============计价成功===================");
                    } else {
                        throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
                    }
                } else {
                    commonWay05(allDose, processingFee, fryingCharge);
                }
            } else {
                commonWay05(allDose, processingFee, fryingCharge);
            }
        }
    }

    private void commonWay05(Integer allDose, Integer processingFee, Integer fryingCharge) {
        log.info("============按照饮片加工费计算======");
        BigDecimal totalMoney = BigDecimalUtils.multiply(BigDecimal.valueOf(allDose), BigDecimal.valueOf(processingFee));
        totalMoney = totalMoney.setScale(0, RoundingMode.HALF_UP);
        log.info("代煎加工费后端计算:{}", totalMoney);
        log.info("代煎加工费前端计算:{}", fryingCharge);
        if (totalMoney.compareTo(new BigDecimal(fryingCharge)) == 0) {
            log.info("============验价成功==============");
        } else {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
        }
    }


    public void commonWay(BigDecimal totalWeight, BigDecimal processPrice, BigDecimal fryingFee, BigDecimal processG) {
        //可能存在一些小的偏差,在-5分到5分之间都算验证通过  保留小数点后2位
        BigDecimal resKg = BigDecimalUtils.divide(totalWeight, processG, 3);
        resKg = resKg.setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalMoney = BigDecimalUtils.multiply(resKg, processPrice);
        log.info("药品重量换算成公斤===============>" + resKg);
        commonWay02(totalMoney, fryingFee);
    }

    public void commonWay02(BigDecimal totalMoney, BigDecimal fryingFee) {
        BigDecimal subtractResult = totalMoney.subtract(fryingFee);
        log.info("后端计算的总价格为===============>" + totalMoney);
        log.info("前端计算的总价格为===============>" + fryingFee);
        log.info("totalMoney-fryingFee相差========>" + subtractResult);
        //可能存在一些小的偏差,在-2分到2分之间都算验证通过
        if (subtractResult.compareTo(BigDecimal.valueOf(-2)) <= 0 || subtractResult.compareTo(BigDecimal.valueOf(2)) >= 0) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "加工费有误");
        }
    }

    /**
     * 发送生成处方pdf消息
     *
     * @param tencode
     * @param tcms
     */
    public void sendPresPdfTaskMQ(String tencode, List<PresCreateDrugsReq> tcms) {
        redisTemplate.opsForValue().set(PRES_TCMS_KEY + tencode, JSON.toJSONString(tcms));
        redisTemplate.expire(PRES_TCMS_KEY + tencode, 1L, TimeUnit.MINUTES);
        rabbitSend.sendMessage(MQConfig.PRES_PDF_EXCHANGE, MQConfig.PRES_PDF_QUERE, tencode);
    }

    /**
     * 生成处方pdf
     *
     * @param tencode
     */
    @Override
    public void generatePresPdf(String tencode) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        PresPrescription pres = getById(tencode);
        String docName = doctorUserService.getDoctorUserName(pres.getDoctorId());
        Integer mechanId = doctorUserService.getDoctorUserMechanId(pres.getDoctorId());
        String json = redisTemplate.opsForValue().get(PRES_TCMS_KEY + tencode);
        List<PresCreateDrugsReq> tcms = JSON.parseArray(json, PresCreateDrugsReq.class);
        log.info("json:{},tcms:{}", json, tcms);
        if (tcms == null) {
            return;
        }
        //转pdf模板文件的模板参数
        Map<String, String> toPdf = new HashMap<>();
        toPdf.put("tencode", pres.getTencode());
        toPdf.put("mechanName", "阿康中医诊所互联网医院");
//        toPdf.put("mechanName", doctorUserService.getDoctorUserOrganization(pres.getDoctorId()));
        toPdf.put("name", pres.getName());
        toPdf.put("sex", pres.getSex());
        toPdf.put("age", pres.getAge());
//        toPdf.put("ks", StringUtils.isBlank(pres.getDepartmentName()) ? "中医科" : pres.getDepartmentName());
        toPdf.put("ks", "中医科");
        toPdf.put("medId", pres.getMedId());
        toPdf.put("phone", pres.getPhoneNum());
        toPdf.put("disease", pres.getDiagnosticName());
        toPdf.put("day", pres.getCreateDate().format(DateUtils.DTF_YMD_HMS));
        toPdf.put("symptomList", pres.getSymptomList());
        StringBuilder sb = new StringBuilder();
        final int[] count = {1};
        tcms.forEach(t -> {
            StringBuilder str = new StringBuilder();
            str.append(t.getHerbName()).append(" ").append(t.getDrugallnum()).append(t.getUnit());
            if (!StringUtils.isBlank(t.getDecocting())) {
                str.append("（").append(t.getDecocting()).append("）");
            }
            if (count[0] == 4) {
                str.append("\r");
                count[0] = 1;
            } else {
                int length = str.toString().length();
                for (int i = 0; i < 14 - length; i++) {
                    str.append(" ");
                }
                count[0]++;
            }
            sb.append(str);
        });

        String type = "";
        if (pres.getType() == PresConstants.DrugsProcessingType.ONE || pres.getType() == PresConstants.DrugsProcessingType.TWO) {
//            toPdf.put("all", String.valueOf(pres.getAllDose()));
//            toPdf.put("sday", String.valueOf(pres.getDayDose()));
//            toPdf.put("dose", String.valueOf(pres.getDoseNum()));
//            toPdf.put("ml", pres.getDrugDose());
            type = "共" + pres.getAllDose() + "剂，每日 " + pres.getDayDose() + "剂，每剂 " + pres.getDoseNum() + " 次，一次 " + pres.getDrugDose() + "毫升";
            String yp = "饮片";
            if (pres.getType() == PresConstants.DrugsProcessingType.ONE) {
                yp += "-代煎";
            } else {
                yp += "-不代煎";
            }
            toPdf.put("spec", yp);
        } else if (pres.getType() == PresConstants.DrugsProcessingType.NINE || pres.getType() == PresConstants.DrugsProcessingType.TEN || pres.getType() == PresConstants.DrugsProcessingType.ELEVEN || pres.getType() == PresConstants.DrugsProcessingType.TWELVE || pres.getType() == PresConstants.DrugsProcessingType.THIRTEEN || pres.getType() == PresConstants.DrugsProcessingType.FOURTEEN || pres.getType() == PresConstants.DrugsProcessingType.FIFTEEN || pres.getType() == PresConstants.DrugsProcessingType.SIXTEEN) {
            //    9.粉剂(40目及以下)
//                10.粉制(60目)
//                11.粉剂(80目)
//                12.粉剂(100目)
//                13.粉剂(150目)
//                14.粉剂(200目)
//                15.合煎制粉(200目)
//                16.粉剂(300目及以上)
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + "包，每包 " + pres.getDoseNum() + " 克，目数 " + pres.getDrugDose() + "目";
            toPdf.put("spec", "粉剂");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.FOUR || pres.getType() == PresConstants.DrugsProcessingType.FIVE || pres.getType() == PresConstants.DrugsProcessingType.SIX || pres.getType() == PresConstants.DrugsProcessingType.SEVEN) {
            //        4.水丸
            //        5.浓缩丸
            //        6.水蜜丸
            //        7.蜜丸
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + " 克";
            toPdf.put("spec", "丸剂");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.EIGHT) {
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + " 包，每包 " + pres.getDoseNum() + " 克";
            toPdf.put("spec", "膏方");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.THREE) {
            type = "共" + pres.getAllDose() + "剂，每天" + pres.getDayDose() + "剂，每日 " + pres.getDoseNum() + " 次，每次 1 袋";
            toPdf.put("spec", "颗粒剂");
        }
        toPdf.put("drugs", sb.toString());
        toPdf.put("num", String.valueOf(tcms.size()));
        toPdf.put("type", type);
        toPdf.put("advice", pres.getIsAiPres() == PresConstants.IsAIPres.YES ? pres.getTreatAdvice() : pres.getAdvice());
        toPdf.put("doctorName", "");
        toPdf.put("amount", BigDecimalUtils.divide(BigDecimal.valueOf(pres.getMoney() + pres.getFryingFee() + pres.getConsultationFee() + pres.getExpensesFee() + pres.getServiceFee()), BigDecimal.valueOf(100)).toString());
        log.info("pdfMap:{}", toPdf);
        List<Integer> drugsPoisonIndex = drugsPoisonService.getDrugsPoisonIndex(tcms);
        ArrayList<WordToPdf.ImagePosition> imgList = new ArrayList<>();
        //医生签名图片
        WordToPdf.ImagePosition signImg = new WordToPdf.ImagePosition();
        signImg.setLevel(320);
        signImg.setVertical(385);
        signImg.setSourceUrl(pres.getSign());
        imgList.add(signImg);
        WordToPdf.ImagePosition sealImg = new WordToPdf.ImagePosition();
        //医院公章图片 地址固定
        sealImg.setLevel(300);
        sealImg.setVertical(420);
        sealImg.setWidth(120);
        sealImg.setHight(116);
        sealImg.setSourceUrl("https://zk-ak.obs.cn-south-1.myhuaweicloud.com/dadao/互联网医院公章.png");
        imgList.add(sealImg);
        if (CollectionUtil.isNotEmpty(drugsPoisonIndex)) {
            //有毒要签字
            drugsPoisonIndex.forEach(i -> {
                WordToPdf.ImagePosition imagePosition = new WordToPdf.ImagePosition();
                imagePosition.setLevel((i % 4) * 88 + 30);
                imagePosition.setVertical((i / 4) * 20 + 180);
                imagePosition.setSourceUrl(pres.getSign());
                imgList.add(imagePosition);
            });
        }
        MultipartFile multipartFile = WordToPdf.createWordToPdf(toPdf, HealthConstants.CommonConstants.WORD_TO_PDF_TEM, imgList);
        String fileInfo = fileInfoService.uploadSingleFileStr(multipartFile, false);
        PresPrescription press = new PresPrescription();
        press.setTencode(tencode);
        press.setPdfUrl(fileInfo);
        updateById(press);
        PresPrescription res = this.getById(tencode);
        if (res == null) {
            return;
        }
        Integer flag = pharmacyService.getPharmacyFlag(res.getPharmId());
        if (flag == PharConstants.Flag.HR) {
            //生成处方图片
            String imageBase64 = "";
            try {
                imageBase64 = PdfToImgUtil.getImagBase64(fileInfo);
                log.info("处方图片BASE64:{}", imageBase64);
            } catch (Exception e) {
                log.info("图片生成BASE64失败");
                e.printStackTrace();
                logErrorService.presBackLog("pdf转图片转BASE失败", "处理PDF转图片转BASE64", "tencode=" + tencode);
                return;
            }
            if (StringUtils.isBlank(imageBase64)) {
                logErrorService.presBackLog("pdf转图片转BASE失败", "处理PDF转图片转BASE64", "tencode=" + tencode);
                return;
            }
            String fix = "data:image/png;base64,";
            imageBase64 = fix + imageBase64;
            //数据过大,暂不存数据库 存入缓存 使用完就删除
            redisTemplate.opsForValue().set(RedisKeyConstants.PRES_IMG_BASE64_KEY + tencode, imageBase64, 24L, TimeUnit.HOURS);
        }
    }

    public void verifyKmDrugDose(Pharmacy pharmacy, PresCreateReq createReq, PatientMedCard medCard) {
        PresCreateKmReq kmReq = (PresCreateKmReq) createReq;
        int age = CalendarUtil.getAge(medCard.getBirthDate());
        if (pharmacy.getName().contains("深圳")) {
            if (kmReq.getIsWithin() == 0) {
                if (age <= 6) {
                    if (kmReq.getPackagenum() != 50 && kmReq.getPackagenum() != 100) {
                        throw new ZekeException(400, "儿童内服只有50ml以及100ml");
                    }
                } else {
                    if (kmReq.getPackagenum() != 200) {
                        throw new ZekeException(400, "成人内服只有200ml");
                    }
                }
            } else {
                if (kmReq.getPackagenum() != 200) {
                    throw new ZekeException(400, "外用只有200ml");
                }
            }
        } else if (pharmacy.getName().contains("普宁")) {
            if (kmReq.getIsWithin() == 0) {
                if (age <= 6) {
                    if (kmReq.getPackagenum() != 80) {
                        throw new ZekeException(400, "儿童内服只有80ml");
                    }
                } else {
                    if (kmReq.getPackagenum() != 150) {
                        throw new ZekeException(400, "成人内服只有150ml");
                    }
                }
            } else {
                if (kmReq.getPackagenum() != 250) {
                    throw new ZekeException(400, "外用只有250ml");
                }
            }
        } else if (pharmacy.getName().contains("成都")) {
            if (kmReq.getIsWithin() == 0) {
                if (age <= 6) {
                    if (kmReq.getPackagenum() != 80 && kmReq.getPackagenum() != 100) {
                        throw new ZekeException(400, "儿童内服只有80ml和100cml");
                    }
                } else {
                    if (kmReq.getPackagenum() != 150) {
                        throw new ZekeException(400, "成人内服只有150ml");
                    }
                }
            } else {
                if (kmReq.getPackagenum() != 250) {
                    throw new ZekeException(400, "外用只有250ml");
                }
            }
        }
    }

    /**
     * 处方退款回调
     *
     * @param pay
     */
    @Override
    public void refundPresCallback(OrderPay pay) {
        log.info("处方退款回调");
        String params = TemplateConstants.TemplateType.THREE_TYPE + "-" + pay.getOrderNo();
        log.info("发送处方退款模板消息,发送参数{}", params);
        rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
    }

    /**
     * 医生审核无处方权处方
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doctorReviewPres(DoctorReviewPresReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        PresPrescription presPrescription = getById(req.getTencode());
        if (presPrescription == null || presPrescription.getStatus() == PresConstants.PresStatus.DEL) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "处方不存在");
        }
        if (presPrescription.getStatus() != PresConstants.PresStatus.DOC_NO_REVIEW) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "处方不在待审方状态");
        }
        if (!presPrescription.getReviewDoctorId().equals(loginInfo.getId())) {
            throw new ZekeException(400, "非该处方审核医生无法审方");
        }
        PresPrescription update = new PresPrescription();
        update.setTencode(req.getTencode());
        update.setStatus(req.getStatus());
        int newsInfoType = 1;
        if (req.getStatus() == PresConstants.PresStatus.NOMER) {
            if (StringUtils.isBlank(req.getReviewSign())) {
                throw new ZekeException(400, "签名-审核医生不能为空");
            }
            if (!StringUtils.isBlank(presPrescription.getReviewConfirmSign()) && StringUtils.isBlank(req.getReviewConfirmSign())) {
                throw new ZekeException(400, "二次签名-审核医生不能为空");
            }
            update.setReviewSign(req.getReviewSign());
            update.setReviewConfirmSign(req.getReviewConfirmSign());
        } else {
            newsInfoType = 2;
            if (StringUtils.isBlank(req.getRejectReason())) {
                throw new ZekeException(400, "拒绝原因不能为空");
            }
        }
        update.setUpdateDate(LocalDateTime.now());
        updateById(update);
        PresReviewRecord presReviewRecord = new PresReviewRecord();
        presReviewRecord.setTencode(req.getTencode());
        presReviewRecord.setStatus(req.getStatus());
        presReviewRecord.setOperId(loginInfo.getId());
        presReviewRecord.setOperType(loginInfo.getType());
        presReviewRecord.setReviewMsg(req.getRejectReason());
        presReviewRecord.setCreateDate(LocalDateTime.now());
        presReviewRecordService.save(presReviewRecord);
        newsInfoService.sendApplyDoctorPresReviewNotice(presPrescription.getDoctorId(), presPrescription.getTencode(), newsInfoType);
    }

    /**
     * 重新提交处方
     *
     * @param tencode
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reSubmitPres(String tencode) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        PresPrescription presPrescription = getById(tencode);
        if (presPrescription == null || presPrescription.getStatus() == PresConstants.PresStatus.DEL) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "处方不存在");
        }
        if (PresConstants.PresStatus.DOC_REVIEW_TIMEOUT != presPrescription.getStatus()) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "当前处方未在超时中,无法重新提交");
        }
        if (!presPrescription.getDoctorId().equals(loginInfo.getId())) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "无法重新提交他人处方");
        }
        Integer[] presPowers = bindReviewPresDoctorService.queryReviewDoctorId(loginInfo.getId());
        if (presPowers[0] == 0) {
            if (presPowers[1] == -1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "未有处方权以及未签约审核医生");
            } else if (presPowers[1] == -2) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "签约审核医生申请中,无法重新提交");
            }
        }
        PresPrescription update = new PresPrescription();
        update.setTencode(tencode);
        update.setReviewDoctorId(presPowers[1]);
        if (presPowers[0] == 1 && !loginInfo.getId().equals(presPrescription.getReviewDoctorId())) {
            update.setReviewDoctorId(presPrescription.getReviewDoctorId());
        }
        update.setStatus(PresConstants.PresStatus.DOC_NO_REVIEW);
        update.setUpdateDate(LocalDateTime.now());
        updateById(update);
        newsInfoService.sendReviewDoctorPresHandleNotice(update.getReviewDoctorId(), presPrescription.getTencode());
        DelayMqVo<String> delayMqVo = new DelayMqVo<>();
        delayMqVo.setT(presPrescription.getTencode());
        delayMqVo.setType(DelayMqVo.DelayMqVoType.PRES_REVIEW_TIMEOUT);
        //毫秒级 10min消息
        long ms = 1000 * 60 * 10;
        rabbitSend.sendMessageDelay(MQConfig.DELAY_EXCHANGE, MQConfig.DELAY_KEY, delayMqVo, ms);
    }

    /**
     * 删除处方
     *
     * @param tencode
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePresStatus(String tencode) {
        PresPrescription presPrescription = getById(tencode);
        if (presPrescription == null || presPrescription.getStatus() == PresConstants.PresStatus.DEL) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "处方不存在");
        }
        if (!PresConstants.PresStatus.canDel.contains(presPrescription.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "当前处方流转中,不能删除");
        }
        PresPrescription update = new PresPrescription();
        update.setTencode(tencode);
        update.setStatus(PresConstants.PresStatus.DEL);
        boolean i = updateById(update);
        if (!i) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
        //删除处方药品
        UpdateWrapper<PresPretrialDrugs> uw = new UpdateWrapper<>();
        uw.lambda().eq(PresPretrialDrugs::getTencode, tencode).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER).set(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.DEL);
        presPretrialDrugsService.update(uw);
        //删除处方订单
        UpdateWrapper<OrderPay> ou = new UpdateWrapper<>();
        ou.lambda().eq(OrderPay::getServerNo, tencode).set(OrderPay::getStatus, OrderConstants.Status.DEL);
        orderPayService.update(ou);
        //清除处方详情缓存
        redisTemplate.delete(RedisKeyConstants.PRES_DETAIL_REDIS_KEY + tencode);
    }

    /**
     * @param req:
     * @return void
     * @author czg
     * @description 取消处方
     * @date 2022/12/2 10:11
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPres(CancelPresReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        PresPrescription presPrescription = getById(req.getTencode());
        if (presPrescription == null || presPrescription.getStatus() == PresConstants.PresStatus.DEL) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "处方不存在");
        }
        if (!PresConstants.PresStatus.canCancel.contains(presPrescription.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "当前处方流转中,不能取消");
        }
        if (presPrescription.getStatus() != PresConstants.PresStatus.NOMER && presPrescription.getStatus() != PresConstants.PresStatus.SENDPHARMERROR) {
            //此处已经将处方发送到了药房, 需要调用药房接口取消处方
            req.setOperName(loginInfo.getName());
            /**
             * 调用药房取消处方接口
             */
            PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(presPrescription.getPharmId());
            if (pharServiceInterface == null) {
                throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "获取药房处理service失败");
            }
            pharServiceInterface.cancelPres(req);
        } else {
            presPrescription.setStatus(PresConstants.PresStatus.CANCEL);
            UpdateWrapper<PresPrescription> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().set(PresPrescription::getStatus, PresConstants.PresStatus.CANCEL).eq(PresPrescription::getTencode, presPrescription.getTencode());
            update(updateWrapper);
        }
        QueryWrapper<OrderPay> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderPay::getServerNo, presPrescription.getTencode()).eq(OrderPay::getStatus, OrderConstants.Status.PAY);
        List<OrderPay> list = orderPayService.list(queryWrapper);
        list.forEach(order -> {
            try {
                orderPayService.refund(order.getOrderNo(), 0);
            } catch (Exception e) {
                e.printStackTrace();
                logErrorService.presBackLog("取消处方退款出现异常,请验证是否要手动处理", "取消处方", "orderNo=" + order.getOrderNo());
            }
        });
        //清除处方详情缓存
        redisTemplate.delete(RedisKeyConstants.PRES_DETAIL_REDIS_KEY + presPrescription.getTencode());
    }

    /**
     * @param msg:
     * @param returnInfo:
     * @param params:
     * @return void
     * @author czg
     * @description 需要手动处理的异常日志
     * @date 2022/12/2 10:50
     */
    public void presBackLog(String msg, String returnInfo, String params) {
        LogError logError = new LogError();
        logError.setMsg(msg);
        logError.setReturnInfo(returnInfo);
        logError.setCreateDate(LocalDateTime.now());
        logError.setParams(params);
        logError.setStatus(LogConstants.ErrorStatus.NOMER);
        logErrorService.save(logError);
    }

    /**
     * 查询处方列表
     *
     * @param req
     * @return
     */
    @Override
    public IPage<PresPrescriptionPageRes> queryPresPrescriptionPage(PresPrescriptionPageReq req) {
        Assert.verifyStatusIdsParam(req.getClass(), req);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        if (loginInfo.getType() == LoginInfo.UserType.DOCTOR) {
            req.setDoctorId(loginInfo.getId());
        }
        IPage<PresPrescriptionPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryPresPrescriptionPage(iPage, req);
        for (PresPrescriptionPageRes item : iPage.getRecords()) {
            item.setStatusText(PresConstants.statusToStatusText(item.getOrderStatus(), item.getStatus()));
        }
        return iPage;
    }

    /**
     * 查询处方列表联合处方草稿查询
     *
     * @param req
     * @return
     */
    @Override
    public IPage<PresPrescriptionHistoryPageRes> queryPresPrescriptionHistoryPage(PresPrescriptionPageReq req) {
        Assert.verifyStatusIdsParam(req.getClass(), req);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        if (loginInfo.getType() == LoginInfo.UserType.DOCTOR) {
            req.setDoctorId(loginInfo.getId());
        }
        IPage<PresPrescriptionHistoryPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryPresPrescriptionHistoryPage(iPage, req);
        for (PresPrescriptionHistoryPageRes item : iPage.getRecords()) {
            item.setStatusText(PresConstants.statusToStatusText(item.getOrderStatus(), item.getStatus()));
        }
        return iPage;
    }

    /**
     * 获取处方详情
     *
     * @param tencode
     * @return
     */
    @Override
    public PresPrescriptionDetailRes getPresDetail(String tencode) {
        String key = RedisKeyConstants.PRES_DETAIL_REDIS_KEY + tencode;
        String json = redisTemplate.opsForValue().get(key);
        if (!StringUtils.isBlank(json)) {
            return JSON.parseObject(json, PresPrescriptionDetailRes.class);
        }
        PresPrescriptionDetailRes res = getBaseMapper().getPresMechanDetail(tencode);
        if (res == null) {
            throw new ZekeException(400, "处方不存在");
        }
        if (PresConstants.IsAIPres.YES == res.getIsAiPres()) {
            AicmsDiagnosticResultDetail result = aicmsDiagnosticResultService.queryDiagnosticsMechan(res.getDiagnosticId());
            if (result == null) {
                throw new ZekeException(400, "诊断结果不存在");
            }
            res.setResult(result);
        }
        if (res.getPharmacistsFlag() == 0) {
            queryPresExtendDetail(res);
        }
        QueryWrapper<PatientMedCard> pa = new QueryWrapper<>();
        pa.lambda().eq(PatientMedCard::getMedId, res.getMedId()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
        PatientMedCard patientMedCard = patientMedCardService.getOne(pa);
        if (patientMedCard == null) {
            res.setPatientMedCard(new PatientMedCard());
        } else {
            res.setPatientMedCard(patientMedCard);
        }
        QueryWrapper<PresPretrialDrugs> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPretrialDrugs::getTencode, res.getTencode());
        qs.lambda().eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> list = presPretrialDrugsService.list(qs);
        res.setDrugs(list);
        //查辅料
        if (res.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            QueryWrapper<PresSaveMaterial> qw = new QueryWrapper<>();
            qw.lambda().eq(PresSaveMaterial::getTencode, res.getTencode()).eq(PresSaveMaterial::getType, PresConstants.DrugsProcessingType.EIGHT);
            List<PresSaveMaterial> presSaveMaterials = presSaveMaterialService.list(qw);
            res.setPresCreateCreamFormulaReqs(presSaveMaterials);
        }
        if (res.getPresType() == PresConstants.DrugsProcessingType.SEVEN || res.getPresType() == PresConstants.DrugsProcessingType.SIX || res.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            //蜜丸和水密丸蜂蜜费用已存在药品费里面
            res.setOtherFee(0);
        }
        QueryWrapper<OrderPay> qo = new QueryWrapper<>();
        qo.lambda().eq(OrderPay::getServerNo, res.getTencode());
        qo.lambda().ne(OrderPay::getStatus, OrderConstants.Status.DEL);
        OrderPay orderPay = orderPayService.getOne(qo);
        if (orderPay == null) {
            res.setOrderPay(new OrderPay());
        } else {
            res.setOrderPay(orderPay);
        }
        if (res.getStatus() == PresConstants.PresStatus.DELIVERY || res.getStatus() == PresConstants.PresStatus.SUC) {
            String[] arr = getPresOutReceiveTime(tencode);
            res.setOutboundDate(arr[0]);
            res.setReceivingTime(arr[1]);
        }
        res.setPresHandleList(presHandleRecordService.queryPresHandleRecordList(tencode));
        res.setFlowListRes(orderPayService.queryOrderFlowListByTencode(tencode));
        res.initAddrRes();
        if (res.getStatus() == PresConstants.PresStatus.DOC_REVIEW_REJECT) {
            res.setRejectReason(getBaseMapper().queryPresReviewRejectReasonLast(tencode));
        }
        redisTemplate.opsForValue().set(key, JSON.toJSONString(res));
        redisTemplate.expire(key, 5L, TimeUnit.SECONDS);
        if (res != null) {
            try {
                res.setStatusText(PresConstants.statusToStatusText(res.getOrderPay().getStatus(), res.getStatus()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return res;
    }

    @Override
    public Boolean isCount(Integer docotorId, Integer pharmId) {
        DoctorUser doctorUser = doctorUserService.getById(docotorId);
        Integer type = doctorUser.getType();
        Integer pharmacyFlag = pharmacyService.getPharmacyFlag(pharmId);
        return type == UserConstants.DoctorUserType.PUB && pharmacyFlag != PharConstants.Flag.STORE && pharmacyFlag != PharConstants.Flag.NOT;
    }

    /**
     * 自动完成订单
     *
     * @param tencode
     */
    @Override
    public void presAutoComplete(String tencode) {
        PresPrescription pres = getById(tencode);
        if (pres.getStatus() != PresConstants.PresStatus.DELIVERY) {
            return;
        }
        Integer pharFlag = pharmacyService.getPharmacyFlag(pres.getPharmId());
        if (pharFlag == PharConstants.Flag.HJT) {
            PresPrescription update = new PresPrescription();
            update.setTencode(tencode);
            update.setUpdateDate(LocalDateTime.now());
            update.setStatus(PresConstants.PresStatus.SUC);
            updateById(update);
            presHjtPharRoamMapper.updatePresCompleteDate(tencode, LocalDateTime.now());
            doctorOrderIncomeDetailService.doctorOrderIncomeEntrySuc(pres.getTencode(), pres.getDoctorId());
        }
    }

    /**
     * @param orderNo: 处方的订单编号
     * @return void
     * @description 处方重新发送至药房
     * @author czg
     * @date 2023/6/18 9:45
     */
    @Override
    public void sendPharAgain(String orderNo) {
        OrderPay orderPay = orderPayService.getById(orderNo);
        if (orderPay == null) {
            throw new ZekeException("订单号不存在");
        }
        PresPrescription presPrescription = getById(orderPay.getServerNo());
        if (presPrescription == null) {
            throw new ZekeException("处方不存在");
        }
        if (presPrescription.getStatus() != PresConstants.PresStatus.SENDPHARMERROR) {
            throw new ZekeException("处方不是发送失败状态,不能继续发送");
        }
        PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(orderPay);
        if (pharServiceInterface == null) {
            //药房处理的service获取失败
            throw new ZekeException("获取药房service失败");
        }
        boolean sendPresToPhar = pharServiceInterface.sendPresToPhar(orderPay);
        if (!sendPresToPhar) {
            throw new ZekeException("发送到药房失败");
        }
    }


    @Autowired
    private IPharExpressRuleService pharExpressRuleService;
    @Autowired
    private IPharSettingTimeService pharSettingTimeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void test() {
        List<PresPrescription> presPrescriptions = this.list();
        Long start1 = System.currentTimeMillis();
        log.info("处方数据开始兼容------------------------------------" + start1);
        if (CollectionUtil.isNotEmpty(presPrescriptions)) {
            presPrescriptions.forEach(item -> {
                LambdaUpdateWrapper<PresPrescription> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(PresPrescription::getType, 1).set(PresPrescription::getOtherFee, 0).set(PresPrescription::getDeliveryIsDisplay, 0).eq(PresPrescription::getTencode, item.getTencode());
                this.update(updateWrapper);
            });
        }
        Long end1 = System.currentTimeMillis();
        log.info("处方数据结束兼容------------------------------------耗时:" + (end1 - start1));
        log.info("开始物流数据----------------------------------------" + end1);
        List<PharExpressRule> pharExpressRuleList = pharExpressRuleService.list();
        if (CollectionUtil.isNotEmpty(pharExpressRuleList)) {
            pharExpressRuleList.forEach(item -> {
                item.setIsInnerCityChecked(0)//做一个默认值
                        .setIsInnerProvincialChecked(0).setIsOutProvincialChecked(0).setDeliverWay(1);
            });
            pharExpressRuleService.updateBatchById(pharExpressRuleList);
        }
        Long end2 = System.currentTimeMillis();
        log.info("结束物流数据兼容----------------------------------------" + (end1 - end2));
        log.info("开始默认药房默认加工类型兼容----------------------------------------" + end2);
        List<PharmacyChoose> pharmacyChooses = pharmacyChooseService.list();
        if (CollectionUtil.isNotEmpty(pharmacyChooses)) {
            pharmacyChooses.forEach(item -> {
                item.setType(1);
            });
            pharmacyChooseService.updateBatchById(pharmacyChooses);
        }
        Long end3 = System.currentTimeMillis();
        log.info("结束默认药房默认加工类型数据兼容 耗时----------------------------------------" + (end3 - end2));
        log.info("处理代煎类型的有效实效----------------------------------------------------" + end3);
        List<PharSettingTime> pharSettingTimes = new ArrayList<>();
        PharSettingTime pharSettingTimes1 = new PharSettingTime();
        pharSettingTimes1.setFlag(1).setType(PresConstants.DrugsProcessingType.ONE).setTime("24小时内");
        PharSettingTime pharSettingTimes2 = new PharSettingTime();
        pharSettingTimes2.setFlag(1).setType(PresConstants.DrugsProcessingType.TEN).setTime("3-5天");
        PharSettingTime pharSettingTimes3 = new PharSettingTime();
        pharSettingTimes3.setFlag(1).setType(PresConstants.DrugsProcessingType.ELEVEN).setTime("3-5天");
        PharSettingTime pharSettingTimes4 = new PharSettingTime();
        pharSettingTimes4.setFlag(1).setType(PresConstants.DrugsProcessingType.TWELVE).setTime("3-5天");
        PharSettingTime pharSettingTimes5 = new PharSettingTime();
        pharSettingTimes5.setFlag(1).setType(PresConstants.DrugsProcessingType.FOURTEEN).setTime("3-5天");
        PharSettingTime pharSettingTimes6 = new PharSettingTime();
        pharSettingTimes6.setFlag(1).setType(PresConstants.DrugsProcessingType.FIFTEEN).setTime("5-7天");
        PharSettingTime pharSettingTimes7 = new PharSettingTime();
        pharSettingTimes7.setFlag(1).setType(PresConstants.DrugsProcessingType.FOUR).setTime("5-7天");
        PharSettingTime pharSettingTimes8 = new PharSettingTime();
        pharSettingTimes8.setFlag(1).setType(PresConstants.DrugsProcessingType.FIVE).setTime("5-10天");
        PharSettingTime pharSettingTimes9 = new PharSettingTime();
        pharSettingTimes9.setFlag(1).setType(PresConstants.DrugsProcessingType.SIX).setTime("5-7天");
        PharSettingTime pharSettingTimes10 = new PharSettingTime();
        pharSettingTimes10.setFlag(1).setType(PresConstants.DrugsProcessingType.SEVEN).setTime("5-10天");
        PharSettingTime pharSettingTimes11 = new PharSettingTime();
        pharSettingTimes11.setFlag(1).setType(PresConstants.DrugsProcessingType.EIGHT).setTime("5-7天");
        pharSettingTimes.add(pharSettingTimes1);
        pharSettingTimes.add(pharSettingTimes2);
        pharSettingTimes.add(pharSettingTimes3);
        pharSettingTimes.add(pharSettingTimes4);
        pharSettingTimes.add(pharSettingTimes5);
        pharSettingTimes.add(pharSettingTimes6);
        pharSettingTimes.add(pharSettingTimes7);
        pharSettingTimes.add(pharSettingTimes8);
        pharSettingTimes.add(pharSettingTimes9);
        pharSettingTimes.add(pharSettingTimes10);
        pharSettingTimes.add(pharSettingTimes11);
        pharSettingTimeService.saveBatch(pharSettingTimes);
    }

    /**
     * 处方订单审核超时
     *
     * @param tencode
     */
    @Override
    public void presReviewTimeout(String tencode) {
        PresPrescription pres = getById(tencode);
        if (pres.getStatus() != PresConstants.PresStatus.DOC_NO_REVIEW) {
            return;
        }
        PresPrescription update = new PresPrescription();
        update.setTencode(tencode);
        update.setStatus(PresConstants.PresStatus.DOC_REVIEW_TIMEOUT);
        updateById(update);
    }

    /**
     * @param req:
     * @return Page<PresPrescriptionMedPageRes>
     * @description 患者在线问诊咨询时查询处方历史诊断
     * @author czg
     * @date 2023/7/17 10:17
     */
    @Override
    public Page<PresPrescriptionMedPageRes> queryPresMedPage(PresPrescriptionMedPageReq req) {
        Page<PresPrescriptionMedPageRes> page = req.pagePojo();
        page = getBaseMapper().queryPresMedPage(page, req);
        return page;
    }

    /**
     * 问诊中处方订单支付成功通知消息
     *
     * @param tencode
     */
    @Override
    public void consultPresPaySuccess(String tencode) {
        PresPrescription presPrescription = getById(tencode);
        if (presPrescription.getConsultId() != null) {
            consultSubscribeService.consultPresPaySuccess(presPrescription.getConsultId());
        }
    }

    /**
     * 发送处方,诊断,病历,患者数据到监管平台
     */
    @Override
    public void sendDDataToSupervise() {
        QueryWrapper<PresPrescription> qw = new QueryWrapper<>();
        LocalDateTime time = LocalDateTime.now();
        String format = time.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        LocalDate localDate = LocalDate.now().minusDays(1);
        List<PresPrescriptionSuperviseRes> resList = getBaseMapper().getDataToSupervise();
        for (int i = 0; i < resList.size(); i++) {
            PresPrescriptionSuperviseRes item = resList.get(i);

            PiPersonReq req = new PiPersonReq();
            req.setJgdm("0Y41940F29AXTM1114");
            req.setKh(item.getMedId());
            req.setKlx("3");
            req.setZjhm(item.getIdCard());
            req.setZjlbdm("01");
            req.setXm(item.getName());
            req.setXbdm("1");
            req.setXbmc(item.getSex());
            req.setHyztdm("10");
            req.setHyztmc(item.getMaritalStatus());
            req.setCsrq(item.getBirthDate());
            req.setMzdm("01");
            req.setMzmc(item.getNationality());
            req.setGjdm("156");
            req.setGjmc("中国");
            req.setSjhm(item.getMedMobileNumber());
            req.setSjscsj(item.getMedCreateDate());
            req.setCxbz("1");
            req.setTimeStamp(format);
            req.setSign(ObjectUtils.pinyinSort(req));
            req.setSign(DigestUtils.md5Hex(req.getSign()));

            HttpHeaders head = new HttpHeaders();
            head.setContentType(MediaType.APPLICATION_JSON_UTF8);
            HttpEntity<String> entity = new HttpEntity<>(JsonUtils.objectToStr(req), head);
            String result = restTemplate.postForObject(superviseProperties.getPipersion(), entity, String.class);
            log.debug("上传监管平台 患者信息上传返回:{}", result);
            ZekeHosResponse<String> zekeHosResponse = JsonUtils.strToObject(result, ZekeHosResponse.class);
            if (zekeHosResponse.getCode() != 2000) {
                //TODO 上传失败
                log.error("上传患者信息到监管平台失败:{}", zekeHosResponse.getMessage());

            }
            MsTreatmentDiagnoseReq reqDia = new MsTreatmentDiagnoseReq();
            reqDia.setJgdm("0Y41940F29AXTM1114");
            reqDia.setKh(item.getMedId());
            reqDia.setKlx("3");
            reqDia.setFwwddm("0Y41940F29AXTM1114");
            reqDia.setZdxxid("01");
            reqDia.setXm(item.getName());
            reqDia.setMzh(item.getTencode());
            reqDia.setXm(item.getName());
            reqDia.setXbdm("1");
            reqDia.setCsrq(item.getBirthDate());
            reqDia.setNls(Integer.valueOf(item.getAge()));
            reqDia.setJzrqsj(item.getCreateDate());
            reqDia.setZdlxbm("22");
            reqDia.setZyzdbm(item.getZyCode());
            reqDia.setZyzdmc(item.getZyName());
            reqDia.setZyzdbmlx("01");
            reqDia.setZdbz("1");
            reqDia.setZdysgh(String.valueOf(item.getDoctorId()));
            reqDia.setZdysxm(item.getDoctorName());
            reqDia.setZdsj(item.getCreateDate());
            reqDia.setSjscsj(item.getCreateDate());
            reqDia.setCxbz("1");
            reqDia.setTimeStamp(format);
            reqDia.setSign(ObjectUtils.pinyinSort(reqDia));
            reqDia.setSign(DigestUtils.md5Hex(reqDia.getSign()));

            HttpEntity<String> entity2 = new HttpEntity<>(JsonUtils.objectToStr(reqDia), head);
            result = restTemplate.postForObject(superviseProperties.getDiagnose(), entity2, String.class);
            log.debug("上传监管平台 患者诊断上传返回:{}", result);
            zekeHosResponse = JsonUtils.strToObject(result, ZekeHosResponse.class);
            if (zekeHosResponse.getCode() != 2000) {
                //TODO 上传失败
                log.error("上传患者诊断到监管平台失败:{}", zekeHosResponse.getMessage());

            }

            MsTreatmentRecordReq recoDia = new MsTreatmentRecordReq();
            recoDia.setJgdm("0Y41940F29AXTM1114");
            recoDia.setKh(item.getMedId());
            recoDia.setKlx("3");
            recoDia.setFwwddm("0Y41940F29AXTM1114");
            recoDia.setJzlx("100");
            recoDia.setXm(item.getName());
            recoDia.setMzh(item.getTencode());
            recoDia.setXm(item.getName());
            recoDia.setXbdm("1");
            recoDia.setCsrq(item.getBirthDate());
            recoDia.setNls(Integer.valueOf(item.getAge()));
            recoDia.setJzrqsj(item.getCreateDate());
            recoDia.setKsbm("1");
            recoDia.setKsmc("中医科");
            recoDia.setCzbzdm("2");
            recoDia.setZs(item.getSymptomList());
            recoDia.setMzzzzddm(item.getZyCode());
            recoDia.setMzzzzdmc(item.getZyName());
            recoDia.setGmsbs("F");
            recoDia.setMzzzzdbmlx("01");
            recoDia.setYzysgh(String.valueOf(item.getDoctorId()));
            recoDia.setYzysqm(item.getDoctorName());
            recoDia.setCzylwsjgdm("0Y41940F29AXTM1114");
            recoDia.setCzylwsjgmc("阿康中医诊所");
            recoDia.setDzcfwjcfdz("F");
            recoDia.setYsdspwjcfdz("F");
            recoDia.setHzdspwjcfdz("F");
            recoDia.setJzrqsj(item.getCreateDate());
            recoDia.setSjscsj(item.getCreateDate());
            recoDia.setCxbz("1");
            recoDia.setTimeStamp(format);
            recoDia.setSign(ObjectUtils.pinyinSort(recoDia));
            recoDia.setSign(DigestUtils.md5Hex(recoDia.getSign()));

            HttpEntity<String> entity3 = new HttpEntity<>(JsonUtils.objectToStr(recoDia), head);

            result = restTemplate.postForObject(superviseProperties.getRecord(), entity3, String.class);
            log.debug("上传监管平台 患者病历上传返回:{}", result);
            zekeHosResponse = JsonUtils.strToObject(result, ZekeHosResponse.class);
            if (zekeHosResponse.getCode() != 2000) {
                //TODO 上传失败
                log.error("上传患者病历到监管平台失败:{}", zekeHosResponse.getMessage());

            }

            MsTreatmentOrderReq orderReq = new MsTreatmentOrderReq();
            orderReq.setJgdm("0Y41940F29AXTM1114");
            orderReq.setKh(item.getMedId());
            orderReq.setKlx("3");
            orderReq.setFwwddm("0Y41940F29AXTM1114");
            orderReq.setCfbh(item.getTencode());
            orderReq.setXm(item.getName());
            orderReq.setMzh(item.getTencode());
            orderReq.setXm(item.getName());
            orderReq.setXbdm("1");
            orderReq.setCsrq(item.getBirthDate());
            orderReq.setNls(Integer.valueOf(item.getAge()));
            orderReq.setJzrqsj(item.getCreateDate());
            orderReq.setCfmxid(item.getTencode());
            orderReq.setCfyxts(7);
            orderReq.setCfklsj(item.getCreateDate());
            orderReq.setCfklksbm("1");
            orderReq.setCfklksmc("中医科");
            orderReq.setJzrqsj(item.getCreateDate());
            orderReq.setYzxmlxdm("1");
            orderReq.setYpcfsx(7);
            orderReq.setZylbdm("1");
            orderReq.setYpid("1");
            orderReq.setCfmxmc("处方药品");
            orderReq.setZyypcf("饮片处方");
            orderReq.setZyypjs(7);
            orderReq.setZyypjzf("水煎");
            orderReq.setZyyyff("内服");
            //单价总金额
            double money = item.getMoney() / 100;
            BigDecimal bg = new BigDecimal(money);
            double dj = item.getMoney() / item.getAllDose() / 100;
            BigDecimal dg = new BigDecimal(dj);
            orderReq.setDj(dg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            orderReq.setZje(bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            orderReq.setCfklysgh(String.valueOf(item.getDoctorId()));
            orderReq.setCfklysqm(item.getDoctorName());
            orderReq.setJzrqsj(item.getCreateDate());
            orderReq.setSjscsj(item.getCreateDate());
            orderReq.setCxbz("1");
            orderReq.setTimeStamp(format);
            orderReq.setSign(ObjectUtils.pinyinSort(orderReq));
            orderReq.setSign(DigestUtils.md5Hex(orderReq.getSign()));

            HttpEntity<String> entity4 = new HttpEntity<>(JsonUtils.objectToStr(orderReq), head);

            result = restTemplate.postForObject(superviseProperties.getOrder(), entity4, String.class);
            log.debug("上传监管平台 患者处方上传返回:{}", result);
            zekeHosResponse = JsonUtils.strToObject(result, ZekeHosResponse.class);
            if (zekeHosResponse.getCode() != 2000) {
                //TODO 上传失败
                log.error("上传患者处方到监管平台失败:{}", zekeHosResponse.getMessage());

            }
        }
    }

    @Override
    public Page<PresBasics> queryPresBasicPage(PresBasicReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        Page<PresBasics> page = req.pagePojo();
        Page<PresBasics> res = this.getBaseMapper().queryPresBasicPage(page, req.getKeyword(), loginInfo.getId());
        return res;
    }

    @Override
    public PayOrderResponse<?> addOrder(String openId, String tencode, String payType, HttpServletRequest request) {
        CreateOrderReq orderReq = new CreateOrderReq();
        orderReq.setPayType(payType);
        orderReq.setOpenid(openId);
        PresPrescription presPrescription = this.getById(tencode);
        if (presPrescription == null) {
            throw new ZekeException("处方不存在!");
        }
        int price = Math.round((presPrescription.getDiscountMoney() == null ? presPrescription.getMoney() : presPrescription.getDiscountMoney()) + presPrescription.getConsultationFee() + presPrescription.getExpensesFee() + presPrescription.getFryingFee() + presPrescription.getServiceFee() + presPrescription.getOtherFee());//加上蜂蜜和辅料
        orderReq.setPrice(price);
        orderReq.setServerNo(tencode);
        orderReq.setPartyId(presPrescription.getPharmId());
        orderReq.setPartyType(2);
        orderReq.setProduct(CS.NOTICE_CHANNEL.PRE);
        PayOrderResponse<?> res = orderPayService.createOrder(request, orderReq, presPrescription.getSourceType());
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("docName", loginInfo.getName());
            jsonObject.put("patName", presPrescription.getName());
            jsonObject.put("medId", presPrescription.getMedId());
            jsonObject.put("createDate", DateUtils.DTF_YMD_HM.format(presPrescription.getCreateDate()));
            jsonObject.put("amount", res.getOrderPay().getActualPay());
            jsonObject.put("tencode", presPrescription.getTencode());
            String params = TemplateConstants.TemplateType.PRES_ORDER_UN_PAY_PAT_GZH + "-" + jsonObject.toJSONString();
            rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
//                templateMessAgeService.sendPresOrderUnPayTemplateMessage(loginInfo.getName(), medCard.getName(), medCard.getMedId(), presPrescription.getCreateDate(), res.getOrderPay().getActualPay());
        } catch (Exception e) {
            e.printStackTrace();
        }
        productUseRecordService.genOrderUpdateProductUseRecord(presPrescription.getTencode(), res.getOrderPay().getOrderNo(), res.getOrderPay().getActualPay());
        return res;
    }


    @Override
    public String signName(String tencode) {
        PresPrescription presPrescription = this.getById(tencode);
        if (presPrescription == null) {
            throw new ZekeException("处方记录不存在");
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        PresPrescription pres = getById(tencode);
        LambdaQueryWrapper<PresPretrialDrugs> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PresPretrialDrugs::getTencode, tencode);
        List<PresPretrialDrugs> tcms = presPretrialDrugsService.list(queryWrapper);
        //转pdf模板文件的模板参数
        Map<String, String> toPdf = new HashMap<>();
        toPdf.put("tencode", pres.getTencode());
        toPdf.put("mechanName", "阿康中医诊所互联网医院");
//        toPdf.put("mechanName", doctorUserService.getDoctorUserOrganization(pres.getDoctorId()));
        toPdf.put("name", pres.getName());
        toPdf.put("sex", pres.getSex());
        toPdf.put("age", pres.getAge());
//        toPdf.put("ks", StringUtils.isBlank(pres.getDepartmentName()) ? "中医科" : pres.getDepartmentName());
        toPdf.put("ks", "中医科");
        toPdf.put("medId", pres.getMedId());
        toPdf.put("phone", pres.getPhoneNum());
        toPdf.put("disease", pres.getDiagnosticName());
        toPdf.put("day", pres.getCreateDate().format(DateUtils.DTF_YMD_HMS));
        toPdf.put("symptomList", pres.getSymptomList());
        StringBuilder sb = new StringBuilder();
        final int[] count = {1};
        tcms.forEach(t -> {
            StringBuilder str = new StringBuilder();
            str.append(t.getHerbName()).append(" ").append(t.getDrugallnum()).append(t.getUnit());
            if (!StringUtils.isBlank(t.getDecocting())) {
                str.append("（").append(t.getDecocting()).append("）");
            }
            if (count[0] == 4) {
                str.append("\r");
                count[0] = 1;
            } else {
                int length = str.toString().length();
                for (int i = 0; i < 14 - length; i++) {
                    str.append(" ");
                }
                count[0]++;
            }
            sb.append(str);
        });

        String type = "";
        if (pres.getType() == PresConstants.DrugsProcessingType.ONE || pres.getType() == PresConstants.DrugsProcessingType.TWO) {
//            toPdf.put("all", String.valueOf(pres.getAllDose()));
//            toPdf.put("sday", String.valueOf(pres.getDayDose()));
//            toPdf.put("dose", String.valueOf(pres.getDoseNum()));
//            toPdf.put("ml", pres.getDrugDose());
            type = "共" + pres.getAllDose() + "剂，每日 " + pres.getDayDose() + "剂，每剂 " + pres.getDoseNum() + " 次，一次 " + pres.getDrugDose() + "毫升";
            String yp = "饮片";
            if (pres.getType() == PresConstants.DrugsProcessingType.ONE) {
                yp += "-代煎";
            } else {
                yp += "-不代煎";
            }
            toPdf.put("spec", yp);
        } else if (pres.getType() == PresConstants.DrugsProcessingType.NINE || pres.getType() == PresConstants.DrugsProcessingType.TEN || pres.getType() == PresConstants.DrugsProcessingType.ELEVEN || pres.getType() == PresConstants.DrugsProcessingType.TWELVE || pres.getType() == PresConstants.DrugsProcessingType.THIRTEEN || pres.getType() == PresConstants.DrugsProcessingType.FOURTEEN || pres.getType() == PresConstants.DrugsProcessingType.FIFTEEN || pres.getType() == PresConstants.DrugsProcessingType.SIXTEEN) {
            //    9.粉剂(40目及以下)
//                10.粉制(60目)
//                11.粉剂(80目)
//                12.粉剂(100目)
//                13.粉剂(150目)
//                14.粉剂(200目)
//                15.合煎制粉(200目)
//                16.粉剂(300目及以上)
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + "包，每包 " + pres.getDoseNum() + " 克，目数 " + pres.getDrugDose() + "目";
            toPdf.put("spec", "粉剂");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.FOUR || pres.getType() == PresConstants.DrugsProcessingType.FIVE || pres.getType() == PresConstants.DrugsProcessingType.SIX || pres.getType() == PresConstants.DrugsProcessingType.SEVEN) {
            //        4.水丸
            //        5.浓缩丸
            //        6.水蜜丸
            //        7.蜜丸
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + " 克";
            toPdf.put("spec", "丸剂");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.EIGHT) {
            type = "每天" + pres.getAllDose() + "次，每次 " + pres.getDayDose() + " 包，每包 " + pres.getDoseNum() + " 克";
            toPdf.put("spec", "膏方");
        } else if (pres.getType() == PresConstants.DrugsProcessingType.THREE) {
            type = "共" + pres.getAllDose() + "剂，每天" + pres.getDayDose() + "剂，每日 " + pres.getDoseNum() + " 次，每次 1 袋";
            toPdf.put("spec", "颗粒剂");
        }
        toPdf.put("drugs", sb.toString());
        toPdf.put("num", String.valueOf(tcms.size()));
        toPdf.put("type", type);
        toPdf.put("advice", pres.getIsAiPres() == PresConstants.IsAIPres.YES ? pres.getTreatAdvice() : pres.getAdvice());
        toPdf.put("doctorName", "");
        if (presPrescription.getFlag() != 1) {
            toPdf.put("amount", "处方总金额(元): " + BigDecimalUtils.divide(BigDecimal.valueOf(pres.getMoney() + pres.getFryingFee() + pres.getConsultationFee() + pres.getExpensesFee() + pres.getServiceFee()), BigDecimal.valueOf(100)).toString());
        } else {
            toPdf.put("amount", "");
        }

        log.info("pdfMap:{}", toPdf);
//        List<Integer> drugsPoisonIndex = getDrugsPoisonIndex(tcms);
        ArrayList<WordToPdf.ImagePosition> imgList = new ArrayList<>();
        WordToPdf.ImagePosition sealImg = new WordToPdf.ImagePosition();
        //医院公章图片 地址固定
        sealImg.setLevel(300);
        sealImg.setVertical(420);
        sealImg.setWidth(120);
        sealImg.setHight(116);
        sealImg.setSourceUrl("https://zk-ak.obs.cn-south-1.myhuaweicloud.com/dadao/互联网医院公章.png");
        imgList.add(sealImg);
        MultipartFile multipartFile = WordToPdf.createWordToPdf(toPdf, HealthConstants.CommonConstants.WORD_TO_PDF_TEM, imgList);
        VisaWaitFileUploadReq visaWaitFileUploadReq = new VisaWaitFileUploadReq();
        List<MultipartFile> files = new ArrayList<>();
        files.add(multipartFile);
        visaWaitFileUploadReq.setContractFiles(files);
        visaWaitFileUploadReq.setContractName("互联网处方");
        visaWaitFileUploadReq.setContractNo(tencode);
        String url = caDoctorService.caSign(visaWaitFileUploadReq);
        presPrescription.setPdfUrl(url);

        Boolean flag = this.updateById(presPrescription);
        if (!flag) {
            throw new ZekeException("更新处方失败");
        }
        PresReviewRecord presReviewRecord = new PresReviewRecord();
        presReviewRecord.setCreateDate(LocalDateTime.now()).setTencode(tencode).setStatus(1).setOperId(presPrescription.getReviewDoctorId()).setOperType(LoginInfo.UserType.DOCTOR);
        Boolean flag1 = presReviewRecordService.save(presReviewRecord);
        if (!flag1) {
            throw new ZekeException("保存审核记录失败");
        }
        String imageBase64 = null;
        try {
            imageBase64 = PdfToImgUtil.getImagBase64(url);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return imageBase64;
    }

    @Autowired
    private IDrugsDirectoryService drugsDirectoryService;


    public List<Integer> getDrugsPoisonIndex(List<PresPretrialDrugs> reqs) {
        Set<Integer> set = new HashSet<>();
        int size = reqs.size();
        for (int i = 0; i < size; i++) {
            PresPretrialDrugs req = reqs.get(i);
            QueryWrapper<DrugsPoison> qw = new QueryWrapper<>();
            qw.lambda().in(DrugsPoison::getHerbName, req.getHerbName()).last("limit 1");
            DrugsPoison one = drugsPoisonService.getOne(qw);
            if (one != null) {
                set.add(i);
            }
            LambdaQueryWrapper<DrugsDirectory> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DrugsDirectory::getHerbName, req.getHerbName()).last("limit 1");
            DrugsDirectory drugsDirectory = drugsDirectoryService.getOne(queryWrapper);
            if (drugsDirectory != null) {
                BigDecimal dosage = BigDecimal.valueOf(req.getDrugallnum());
                if (dosage.intValue() > drugsDirectory.getMaxDose().intValue()) {
                    set.add(i);
                }
            }
        }
        List<Integer> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(set)) {
            list.addAll(set);
        }
        return list;

    }

    @Override
    public String savePharmacistsPres(PresPharmacistsReq req) {
        log.info("药师参数:{}", JSON.toJSONString(req));
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.DOCTOR).get();
        Integer type = doctorUserService.getDoctorUserType(loginInfo.getId());
        if (type != UserConstants.DoctorUserType.PRO && type != UserConstants.DoctorUserType.PUB) {
            throw new ZekeException(400, "无权限访问接口");
        }
        Integer[] presPowers = bindReviewPresDoctorService.queryReviewDoctorId(loginInfo.getId());
        if (presPowers[0] == 0) {
            if (presPowers[1] == -1) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "未有处方权以及未签约审核医生");
            } else if (presPowers[1] == -2) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "签约审核医生申请中,无法开方");
            }
        }
        log.info("ai开方诊断id为:{}", req.getDiagnosticId());
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES && req.getDiagnosticId() == null) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "ai开方诊断id不能为空");
        }
        String tencode;
        AicmsDiagnosticResult result = null;
        tencode = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, "CF");
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES) {
            result = aicmsDiagnosticResultService.getById(req.getDiagnosticId());
            if (result == null) {
                throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "诊断结果不存在");
            }
            PresPrescription presPrescription = this.getById(result.getTencode());
            if (presPrescription != null) {
                AicmsDiagnosticResult newResult = new AicmsDiagnosticResult();
                BeanUtils.copyProperties(req, newResult);
                newResult.setCreateTime(LocalDateTime.now());
                newResult.setTencode(tencode);
                aicmsDiagnosticResultService.save(newResult);
                req.setDiagnosticId(newResult.getId());
            }
        }
        req.setIsUpdate(0);
        if (req.getTencode() != null && req.getIsUpdate() == 1) {
            tencode = req.getTencode();
        } else {
            req.setTencode(tencode);
        }
        PatientMedCard medCard;
        if (!StringUtils.isBlank(req.getMedId())) {
            QueryWrapper<PatientMedCard> qw = new QueryWrapper<>();
            qw.lambda().eq(PatientMedCard::getMedId, req.getMedId()).eq(PatientMedCard::getStatus, UserConstants.MedCardStatus.NORMAL);
            medCard = patientMedCardService.getOne(qw);
            if (medCard == null) {
                throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "就诊卡不存在");
            }
            doctorPatientBindService.doctorPatientBind(loginInfo.getId(), medCard.getMedId(), 1);
        } else {
            if (req.getPatientReq() == null) {
                throw new ZekeException(400, "患者信息不能为空");
            }
            medCard = patientMedCardService.addPresGeneratePatientInfo(req.getPatientReq(), req.getAddrReq(), loginInfo);
            req.setMedId(medCard.getMedId());
        }
        log.info("出生日期更改前" + medCard);
        if (medCard.getBirthDate() == null) {
            medCard.setBirthDate(LocalDate.of(1998, 10, 1));
        }
        log.info(medCard.toString());
        if (req.getPatientReq() != null) {
            BeanUtils.copyProperties(req.getPatientReq(), medCard);
        }
        medCard.setPregnant(req.getPregnant());
        if (medCard.getBirthDate() == null) {
            medCard.setBirthDate(LocalDate.of(1998, 10, 1));
        }
        log.info(medCard.toString());
        QueryWrapper<PresPrescription> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPrescription::getTencode, tencode).eq(PresPrescription::getStatus, PresConstants.PresStatus.NOMER);
        PresPrescription presPrescription = getOne(qs);
        if (presPrescription != null) {
            //已存在,修改处方
            if (req.getIsUpdate() == 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方已存在");
            }
        }
        presPrescription = new PresPrescription();
        presPrescription.setEthnicity(medCard.getNationality());
        //保存处方药品
        QueryWrapper<PresPretrialDrugs> q2 = new QueryWrapper<>();
        q2.lambda().eq(PresPretrialDrugs::getTencode, tencode).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> drugList = presPretrialDrugsService.list(q2);
        if (drugList != null && !drugList.isEmpty()) {
            if (req.getIsUpdate() == 0) {
                throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方药品已存在");
            } else {
                UpdateWrapper<PresPretrialDrugs> uw = new UpdateWrapper<>();
                uw.lambda().eq(PresPretrialDrugs::getTencode, tencode).set(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.DEL);
                presPretrialDrugsService.update(uw);
            }
        }
        List<PresPretrialDrugs> drugsList = new LinkedList<>();
        for (PresCreateDrugsReq tcm : req.getTcms()) {
            PresPretrialDrugs drug = new PresPretrialDrugs();
            BeanUtils.copyProperties(tcm, drug);
            drug.setOriginalPrice(0d);
            drug.setTencode(tencode);
            drug.setStatus(PresConstants.PresDrugsStatus.NOMER);
            drugsList.add(drug);
            tcm.setDiscountPrice(tcm.getRetailprice());
        }
        //批量插入
        boolean j = presPretrialDrugsService.saveBatch(drugsList);
        if (!j) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方药品保存失败");
        }
        BeanUtils.copyProperties(req, presPrescription);
        String diagnosticName;
        if (req.getIsAiPres() == PresConstants.IsAIPres.YES) {
            //获取中医诊断名称
            diagnosticName = getDiagnosticName(result);
            req.setDiagnosticName(diagnosticName);
        } else {
            diagnosticName = req.getDisease();
            req.setDiagnosticName(diagnosticName);
        }
        if (result != null) {
            BeanUtils.copyProperties(result, presPrescription);
            presPrescription.setTencode(tencode);
        }
//        log.info("保存处方:{},药品原价", drugOriginalFree);
        presPrescription.setDiagnosticName(diagnosticName);
        presPrescription.setPresOriginalMoney(0);
        presPrescription.setType(req.getPresType());
        presPrescription.setName(medCard.getName());
        presPrescription.setAge(String.valueOf(medCard.getBirthDate().until(LocalDate.now()).getYears()));
        presPrescription.setSex(medCard.getSex());
        presPrescription.setDiagnosticId(req.getDiagnosticId());
        presPrescription.setDepartmentName(req.getDepName());
        presPrescription.setDiseaseName(req.getDisease());
        presPrescription.setMaritalStatus(medCard.getMaritalStatus());
        presPrescription.setPhoneNum(medCard.getMobileNumber());
        presPrescription.setCreateDate(LocalDateTime.now());
        presPrescription.setStatus(PresConstants.PresStatus.NOMER);
        presPrescription.setDoctorId(loginInfo.getId());
        presPrescription.setPharmId(0);//药师开方没有药房 0代替
        presPrescription.setOfflineDisease(req.getOfflineDisease());
        presPrescription.setFlag(1);//药师开方标志
        presPrescription.setIsFree(1);
        presPrescription.setIsFrying(req.getIsFrying());
        if (presPowers[0] == 1) {
            presPrescription.setReviewDoctorId(presPowers[1]);
            presPrescription.setReviewSign(presPrescription.getSign());
            presPrescription.setReviewConfirmSign(presPrescription.getConfirmSign());
        } else {
            presPrescription.setReviewDoctorId(presPowers[1]);
            presPrescription.setStatus(PresConstants.PresStatus.DOC_NO_REVIEW);
        }
        boolean i = saveOrUpdate(presPrescription);
        if (!i) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "处方保存失败");
        }
        Integer doctorId = presPrescription.getDoctorId();
        LambdaQueryWrapper<DoctorDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DoctorDetail::getDoctorId, doctorId);
        DoctorDetail doctorDetail = doctorDetailService.getOne(queryWrapper);
        //创建产品使用记录
        ProductUseRecord record = new ProductUseRecord();
        record.setTencode(tencode).setCreateDate(LocalDateTime.now()).setDoctorId(loginInfo.getId()).setDiseaseName(presPrescription.getDiseaseName()).setDoctorName(doctorDetail.getName()).setDoctorAccount(doctorDetail.getMobileNumber()).setPatientName(presPrescription.getName()).setType(1);
        productUseRecordService.createProductUseRecord(record);
        return tencode;
    }

    @Autowired
    private IDoctorDetailService doctorDetailService;


    @Override
    public void addPharmacistsOrder(String tencode) {
        CreateOrderReq orderReq = new CreateOrderReq();
        PresPrescription presPrescription = this.getById(tencode);
        if (presPrescription == null) {
            throw new ZekeException("处方不存在!");
        }
        orderReq.setPrice(0);
        orderReq.setServerNo(tencode);
        orderReq.setPartyId(0);
        orderReq.setProduct(CS.NOTICE_CHANNEL.PRE);
        Integer sourceType = presPrescription.getSourceType();
        String orderNo = "";
        //线上问诊医生及智能处方编号
        if (sourceType != null && (sourceType == 3 || sourceType == 4)) {
            orderNo = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, orderPrefix.getPrePayPrefix());
        } else if (sourceType != null && sourceType == 5) {//问诊订单编号
            orderNo = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, orderPrefix.getWzOrderPayPrefix());
        } else { //线下医生开方,智能处方编号
            orderNo = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, orderPrefix.getPayPrefix());
        }
        OrderPay orderPay = new OrderPay();
        orderPay.setStatus(OrderConstants.Status.NOPAY);
        orderPay.setOrderNo(orderNo);
        orderPay.setTotalFee(0);
        orderPay.setActualPay(0);
        orderPay.setServerNo(tencode);
        orderPay.setProduct("pre");
        orderPay.setPayParamId(0);
        orderPay.setStatus(2);
        boolean flag = orderPayService.save(orderPay);
        if (!flag) {
            throw new ZekeException(ExceptionEnum.PRES_CREATE_ERROR, "订单创建失败");
        }
        CreateFlowReq flowReq = new CreateFlowReq();
        flowReq.setOrderNo(orderNo);
        flowReq.setPrice(0);
        OrderFlow flow = new OrderFlow();
        //生成唯一订单流水编号
        String flowNo = SerialNumberUtils.getInstance().generateSerialNumber(redisTemplate, orderPrefix.getFlowPrefix());
        flow.setFlowNo(flowNo);
        flow.setOrderNo(orderPay.getOrderNo());
        flow.setTotalFee(0);
        flow.setFlowType(OrderConstants.FlowType.PAY);
        flow.setCreateDate(LocalDateTime.now());
        flow.setStatus(OrderConstants.FlowStatus.PAY);
        Boolean flag1 = orderFlowService.save(flow);
        if (!flag1) {
            throw new ZekeException("保存流水失败");
        }
        presPrescription.setStatus(9);
        this.updateById(presPrescription);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("docName", loginInfo.getName());
            jsonObject.put("patName", presPrescription.getName());
            jsonObject.put("medId", presPrescription.getMedId());
            jsonObject.put("createDate", DateUtils.DTF_YMD_HM.format(presPrescription.getCreateDate()));
            jsonObject.put("amount", 0);
            jsonObject.put("tencode", presPrescription.getTencode());
            String params = TemplateConstants.TemplateType.PRES_ORDER_UN_PAY_PAT_GZH + "-" + jsonObject.toJSONString();
            rabbitSend.sendMessage(MQConfig.TEMPLATE_EXCHANGE, MQConfig.TEMPLATE_QUEUE, params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        productUseRecordService.genOrderUpdateProductUseRecord(presPrescription.getTencode(), orderNo, 0);
        doctorEquityService.saveDoctorEquity(orderPay, 1);
        doctorEquityService.saveDoctorEquity(orderPay, 2);
    }


    public void queryPresExtendDetail(PresPrescriptionDetailRes res) {
        switch (res.getFlag()) {
            case PharConstants.Flag.HJT:
                QueryWrapper<PresHjtDetail> qp1 = new QueryWrapper<>();
                qp1.lambda().eq(PresHjtDetail::getTencode, res.getTencode());
                PresHjtDetail presHjtDetail = presHjtDetailService.getOne(qp1);
                if (presHjtDetail == null) {
                    res.setPresHjtDetail(new PresHjtDetail());
                } else {
                    res.setPresHjtDetail(presHjtDetail);
                }
                break;
            case PharConstants.Flag.DSL:
                QueryWrapper<PresDslDetail> qp2 = new QueryWrapper<>();
                qp2.lambda().eq(PresDslDetail::getTencode, res.getTencode());
                PresDslDetail presDslDetail = presDslDetailService.getOne(qp2);
                if (presDslDetail == null) {
                    res.setPresDslDetail(new PresDslDetail());
                } else {
                    res.setPresDslDetail(presDslDetail);
                }
                break;
            case PharConstants.Flag.KM:
                QueryWrapper<PresKmDetail> qp3 = new QueryWrapper<>();
                qp3.lambda().eq(PresKmDetail::getTencode, res.getTencode());
                PresKmDetail presKmDetail = presKmDetailService.getOne(qp3);
                if (presKmDetail == null) {
                    res.setPresKmDetail(new PresKmDetail());
                } else {
                    res.setPresKmDetail(presKmDetail);
                }
                break;
            case PharConstants.Flag.STORE:
                QueryWrapper<PresOtherDetail> qw4 = new QueryWrapper<>();
                qw4.lambda().eq(PresOtherDetail::getTencode, res.getTencode());
                PresOtherDetail presOtherDetail = presOtherDetailService.getOne(qw4);
                if (presOtherDetail == null) {
                    res.setPresOtherDetail(new PresOtherDetail());
                } else {
                    res.setPresOtherDetail(presOtherDetail);
                }
            case PharConstants.Flag.YF:
                QueryWrapper<PresYfDetail> qw5 = new QueryWrapper<>();
                qw5.lambda().eq(PresYfDetail::getTencode, res.getTencode());
                PresYfDetail presYfDetail = presYfDetailService.getOne(qw5);
                if (presYfDetail == null) {
                    res.setPresYfDetail(new PresYfDetail());
                } else {
                    res.setPresYfDetail(presYfDetail);
                }
            case PharConstants.Flag.HR:
                QueryWrapper<PresHrDetail> qw6 = new QueryWrapper<>();
                qw6.lambda().eq(PresHrDetail::getTencode, res.getTencode());
                PresHrDetail presHrDetail = presHrDetailService.getOne(qw6);
                if (presHrDetail == null) {
                    res.setPresHrDetail(new PresHrDetail());
                } else {
                    res.setPresHrDetail(presHrDetail);
                }
            default:
        }
    }

    public String[] getPresOutReceiveTime(String tencode) {
        Map<String, String> map = getBaseMapper().getPresOutReceiveTime(tencode);
        log.info("map:{}", map);
        if (map == null) {
            return new String[]{null, null};
        }
        return new String[]{map.get("outbound_date"), map.get("receiving_time")};
    }

    /**
     * 通用处方状态流转接口
     *
     * @param req
     * @return
     */
    @Override
    public Object statusReport(CallbackPresStatusReq req) {
        PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(PharEnum.getByHead(req.getFlag()));
        if (pharServiceInterface == null) {
            throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "获取药房处理service失败");
        }
        return pharServiceInterface.presCallback(req);
    }

    /**
     * 通用物流回调接口信息
     *
     * @param req
     * @return
     */
    @Override
    public Object expressCallback(CommonParamReq req) {
        PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(PharEnum.getByHead(req.getFlag()));
        if (pharServiceInterface == null) {
            throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "获取药房处理service失败");
        }
        return pharServiceInterface.expressCallback(req);
    }

    /**
     * 宏济堂药品对账结算
     *
     * @param req
     */
    @Override
    public void hjtReconciliation(SynchHjtPresReq req) {
        Pharmacy pharmacy = pharmacyService.getById(req.getId());
        if (pharmacy == null) {
            throw new ZekeException(ZkExceptionEnum.PARAMETER_ERROR, "药房不存在");
        }
        QueryWrapper<PharmacyDocking> qd = new QueryWrapper<>();
        qd.lambda().eq(PharmacyDocking::getPharId, pharmacy.getId()).eq(PharmacyDocking::getStatus, PharConstants.DockingStatus.NOMER);
        PharmacyDocking pharmacyDocking = pharmacyDockingService.getOne(qd);
        if (pharmacyDocking == null) {
            //药房为空, 数据异常 ,退款
            throw new ZekeException("药房数据为空");
        }
        String json = JsonUtils.objectToStr(SynchHjtPresReq.class);
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> formEntity = new HttpEntity<>(json, headers);
        String data = restTemplate.postForEntity(pharmacyDocking.getSettlementUrl(), formEntity, String.class).getBody();
        //返回的json首尾会带" 去掉
        if (data.startsWith("\"")) {
            data = data.substring(1);
        }
        if (data.endsWith("\"")) {
            data = data.substring(0, data.length() - 1);
        }
        data = data.replaceAll("\\\\", "");
        log.info("药房返回:{}", data);
        HjtResponseVo hjtResponseVo = null;
        try {
            hjtResponseVo = JsonUtils.parse(data, HjtResponseVo.class);
        } catch (Exception e) {
            log.info("宏济堂药房对账解析json失败");
            e.printStackTrace();
        }
    }

    /**
     * 查询处方订单信息h5
     *
     * @param tencode
     * @return
     */
    @Override
    public PresDetailH5Res queryPresDetailH5(String tencode) {
        PresDetailH5Res res = getBaseMapper().queryPresDetailH5(tencode);
        if (res == null) {
            return new PresDetailH5Res();
        }
        if (!StringUtils.isBlank(res.getAddr())) {
            AddrUtils.AddrEntity addrEntity = AddrUtils.getAddrEntity(res.getAddr());
            if (addrEntity.getFlag() == 1) {
                res.setProvince(addrEntity.getProvince());
                res.setCity(addrEntity.getCity().replaceFirst(",", ""));
                res.setDistrict(addrEntity.getDistrict().replaceFirst(",", ""));
                res.setAddr(addrEntity.getAddr().replaceFirst(",", ""));
            }
        }
        if (PresConstants.IsAIPres.YES == res.getIsAiPres()) {
            AicmsDiagnosticResultDetail result = aicmsDiagnosticResultService.queryDiagnosticsMechan(res.getDiagnosticId());
            res.setResult(result);
        }
        //查药材
        QueryWrapper<PresPretrialDrugs> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPretrialDrugs::getTencode, tencode);
        qs.lambda().eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> drugList = presPretrialDrugsService.list(qs);
        res.setDrugs(drugList);
        //查辅料
        if (res.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            LambdaQueryWrapper<PresSaveMaterial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PresSaveMaterial::getTencode, tencode).eq(PresSaveMaterial::getType, PresConstants.DrugsProcessingType.EIGHT);
            List<PresSaveMaterial> list = presSaveMaterialService.list(wrapper);
            res.setPresCreateCreamFormulaReqs(list);
        }
        if (res.getPresType() == PresConstants.DrugsProcessingType.SIX || res.getPresType() == PresConstants.DrugsProcessingType.SEVEN || res.getPresType() == PresConstants.DrugsProcessingType.EIGHT) {
            //蜜丸和水蜜丸蜂蜜加工费已在药品费里面
            res.setOtherFee(0);
        }
        return res;
    }

    /**
     * 修改处方患者收货地址信息
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePresPatientAddrInfo(PayUnOrderReq req) {
        if (req.getExpensesFee() != null) {
            UpdateWrapper<PresPrescription> uw = new UpdateWrapper<>();
            uw.lambda().eq(PresPrescription::getTencode, req.getTencode());
            uw.lambda().set(PresPrescription::getExpensesFee, req.getExpensesFee());
            update(uw);
        }
        //更新地址字段
        UpdateAddressReq addressReq = new UpdateAddressReq();
        addressReq.setAddr(req.getAddr() == null ? "" : req.getAddr()).setCity(req.getCity() == null ? "" : req.getCity()).setDistrict(req.getDistrict() == null ? "" : req.getDistrict()).setProvince(req.getProvince() == null ? "" : req.getProvince()).setMobileNumber(req.getMobileNumber() == null ? "" : req.getMobileNumber()).setReceiver(req.getReceiver() == null ? "" : req.getReceiver());
        String addressJson = JSON.toJSONString(addressReq);
        if (StringUtils.isNotBlank(addressJson)) {
            UpdateWrapper<PresPrescription> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(PresPrescription::getTencode, req.getTencode());
            updateWrapper.lambda().set(PresPrescription::getAddress, addressJson);
            update(updateWrapper);
        }
        PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(req.getTencode());
        if (pharServiceInterface == null) {
            throw new ZekeException(ZkExceptionEnum.CANCEL_PRES_ERROR, "获取药房处理service失败");
        }
        PresPatientAddrReq addrReq = new PresPatientAddrReq();
        BeanUtils.copyProperties(req, addrReq);
        pharServiceInterface.updatePresPatientAddrInfo(addrReq);
        try {
            QueryWrapper<PresPretrialDrugs> qw = new QueryWrapper<>();
            qw.lambda().eq(PresPretrialDrugs::getTencode, req.getTencode());
            qw.lambda().eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
            List<PresPretrialDrugs> list = presPretrialDrugsService.list(qw);
            if (list == null || list.isEmpty()) {
                return;
            }
            List<PresCreateDrugsReq> tcms = JSON.parseArray(JSON.toJSONString(list), PresCreateDrugsReq.class);
            sendPresPdfTaskMQ(req.getTencode(), tcms);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询物流信息
     *
     * @param tencode
     * @return
     */
    @Override
    public List<ExpressRes> queryLogisticsInfo(String tencode) {
        PharServiceInterface pharServiceInterface = pharServiceBeanInterface.getPharService(tencode);
        if (pharServiceInterface == null) {
            throw new ZekeException(400, "获取药房处理service失败");
        }
        return pharServiceInterface.queryLogisticsInfo(tencode);
    }

    /**
     * 处理处方流转状态 药房后台
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handlePresPharmacy(HandlePresPharmacyReq req) {
        PresPrescription pres = getById(req.getTencode());
        if (pres == null) {
            throw new ZekeException(400, "处方数据异常");
        }
        PresPrescription update = new PresPrescription();
        switch (req.getStatus()) {
            case PresConstants.PresStatus.AUDIT:
            case PresConstants.PresStatus.AUDITNO:
                if (pres.getStatus() != PresConstants.PresStatus.SENDPHARM) {
                    throw new ZekeException(400, "处方不在未审核状态,无法进行审核");
                }
                if (req.getStatus() == PresConstants.PresStatus.AUDITNO && StringUtils.isBlank(req.getRejectReason())) {
                    throw new ZekeException(400, "拒绝原因不能为空");
                }
                break;
            case PresConstants.PresStatus.ADJUST:
                if (pres.getStatus() != PresConstants.PresStatus.AUDIT) {
                    throw new ZekeException(400, "处方不在未调剂状态,无法进行调剂");
                }
                break;
            case PresConstants.PresStatus.DELIVERY:
                if (pres.getStatus() != PresConstants.PresStatus.ADJUST) {
                    if (pres.getStatus() != PresConstants.PresStatus.DELIVERY) {
                        throw new ZekeException(400, "处方不已调剂或在已发货状态,无法进行修改物流");
                    }
                }
                update.setExpressno(req.getExpressno());
                update.setExpresscompany(req.getExpresscompany());
                break;
            case PresConstants.PresStatus.CANCEL:
                if (pres.getStatus() != PresConstants.PresStatus.AUDIT) {
                    throw new ZekeException(400, "处方不在未调剂状态,无法进行退款");
                }
                break;
            default:
        }
        update.setTencode(req.getTencode());
        update.setStatus(req.getStatus());
        update.setUpdateDate(LocalDateTime.now());
        updateById(update);
        presHandleRecordService.addPresHandleRecord(req);
        if (update.getStatus() == PresConstants.PresStatus.AUDITNO || update.getStatus() == PresConstants.PresStatus.CANCEL) {
            orderPayService.refund(orderPayService.queryOrderNoByServerNo(update.getTencode()), 0);
        }
    }


    /**
     * @param pres:
     * @return void
     * @description 锁定库存
     * @author czg
     * @date 2023/4/20 15:35
     */
    @Override
    public void checkPresDrugsStock(PresPrescription pres) {
        QueryWrapper<PresPretrialDrugs> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPretrialDrugs::getTencode, pres.getTencode()).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> tcms = presPretrialDrugsService.list(qs);
        if (tcms == null || tcms.isEmpty()) {
            return;
        }
        //创建redisson锁, 默认30s有效期, 会自动续期,会启动一个后台线程,10s扫描一次,锁还存在就在续期30s
        RLock helloLock = redissonClient.getLock(HealthConstants.CommonConstants.STOCK_REDUCE_LOCK);
        try {
            helloLock.lock(12, TimeUnit.SECONDS);
            tcms.forEach(drug -> {
                QueryWrapper<DrugsModel> qw = new QueryWrapper<>();
                qw.lambda().eq(DrugsModel::getDrugnum, drug.getDrugnum()).eq(DrugsModel::getStatus, PresConstants.ModelDrugsStatus.NOMER).eq(DrugsModel::getPharId, pres.getPharmId());
                DrugsModel one = drugsModelService.getOne(qw);
                if (one == null) {
                    throw new ZekeException(drug.getHerbName() + "不存在");
                }
                //判断当前锁定的库存+当前药品的用量是否大于药品库存
                BigDecimal stockQty = one.getStockQty() == null ? new BigDecimal(0) : one.getStockQty();
//                if (one.getQty().compareTo((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))) < 0) {
//                    throw new ZekeException(drug.getHerbName() + "库存不足, 请联系药房增加库存或切换药品");
//                }
                if (one.getQty().compareTo((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose())).add(stockQty)) < 0) {
                    throw new ZekeException(drug.getHerbName() + "库存不足, 请联系药房增加库存或切换药品");
                }
//                one.setQty(one.getQty().subtract((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))));
                //锁定库存  锁定库存+当前药品用量
                one.setStockQty(new BigDecimal(drug.getDrugallnum()).multiply(new BigDecimal(pres.getAllDose())).add(stockQty));
                boolean updateById = drugsModelService.updateById(one);
                if (!updateById) {
                    throw new ZekeException(drug.getHerbName() + "库存锁定失败");
                }
            });
        } catch (ZekeException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException("库存扣减失败");
        } finally {
            helloLock.unlock();
        }
    }

    /**
     * @param pres:
     * @return void
     * @description 解锁库存
     * @author czg
     * @date 2023/4/20 15:35
     */
    @Override
    public void releasePresDrugsStock(PresPrescription pres, Integer type) {
        QueryWrapper<PresPretrialDrugs> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPretrialDrugs::getTencode, pres.getTencode()).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> tcms = presPretrialDrugsService.list(qs);
        if (tcms == null || tcms.isEmpty()) {
            return;
        }
        //创建redisson锁, 默认30s有效期, 会自动续期,会启动一个后台线程,10s扫描一次,锁还存在就在续期30s
        RLock helloLock = redissonClient.getLock(HealthConstants.CommonConstants.STOCK_REDUCE_LOCK);
        try {
            helloLock.lock(12, TimeUnit.SECONDS);
            tcms.forEach(drug -> {
                QueryWrapper<DrugsModel> qw = new QueryWrapper<>();
                qw.lambda().eq(DrugsModel::getDrugnum, drug.getDrugnum()).eq(DrugsModel::getStatus, PresConstants.ModelDrugsStatus.NOMER).eq(DrugsModel::getPharId, pres.getPharmId());
                DrugsModel one = drugsModelService.getOne(qw);
                if (one != null) {
                    if (type == LoginInfo.UserType.DOCTOR) {//医生取消的订单重新添加上失去的库存
                        one.setQty(one.getQty().add((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))));
                    } else if (type == LoginInfo.UserType.ADMIN) {//延时队列过来 直接减去锁定的库存
                        one.setStockQty(one.getStockQty().subtract((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))));
                    }
                    boolean updateById = drugsModelService.updateById(one);
                    if (!updateById) {
                        logErrorService.presBackLog("库存解锁失败", "库存解锁失败", "code=" + drug.getDrugnum());
                    }
                }

            });
        } catch (ZekeException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException("库存解锁失败");
        } finally {
            helloLock.unlock();
        }
    }

    @Override
    public void subQty(PresPrescription pres) {
        QueryWrapper<PresPretrialDrugs> qs = new QueryWrapper<>();
        qs.lambda().eq(PresPretrialDrugs::getTencode, pres.getTencode()).eq(PresPretrialDrugs::getStatus, PresConstants.PresDrugsStatus.NOMER);
        List<PresPretrialDrugs> tcms = presPretrialDrugsService.list(qs);
        if (tcms == null || tcms.isEmpty()) {
            return;
        }
        //创建redisson锁, 默认30s有效期, 会自动续期,会启动一个后台线程,10s扫描一次,锁还存在就在续期30s
        RLock helloLock = redissonClient.getLock(HealthConstants.CommonConstants.STOCK_REDUCE_LOCK);
        try {
            helloLock.lock(12, TimeUnit.SECONDS);
            tcms.forEach(drug -> {
                QueryWrapper<DrugsModel> qw = new QueryWrapper<>();
                qw.lambda().eq(DrugsModel::getDrugnum, drug.getDrugnum()).eq(DrugsModel::getStatus, PresConstants.ModelDrugsStatus.NOMER).eq(DrugsModel::getPharId, pres.getPharmId());
                DrugsModel one = drugsModelService.getOne(qw);
                if (one == null) {
                    throw new ZekeException(drug.getHerbName() + "不存在");
                }
                if (one.getQty().compareTo((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))) < 0) {
                    throw new ZekeException(drug.getHerbName() + "库存不足, 请联系药房增加库存或切换药品");
                }
                //扣减库存
                one.setQty(one.getQty().subtract((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))));
                //扣减锁定中的库存
                one.setStockQty(one.getStockQty().subtract((new BigDecimal(drug.getDrugallnum())).multiply(new BigDecimal(pres.getAllDose()))));
                boolean updateById = drugsModelService.updateById(one);
                if (!updateById) {
                    throw new ZekeException(drug.getHerbName() + "库存扣减失败");
                }
            });
        } catch (ZekeException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException("库存扣减失败");
        } finally {
            helloLock.unlock();
        }
    }
}
